blob: 5a7bb5ce2cf1c40f63dc814914f2ebf738953801 [file] [log] [blame]
John Kessenich140f3df2015-06-26 16:58:36 -06001//
John Kessenich927608b2017-01-06 12:34:14 -07002// Copyright (C) 2014-2015 LunarG, Inc.
3// Copyright (C) 2015-2016 Google, Inc.
John Kessenich140f3df2015-06-26 16:58:36 -06004//
John Kessenich927608b2017-01-06 12:34:14 -07005// All rights reserved.
John Kessenich140f3df2015-06-26 16:58:36 -06006//
John Kessenich927608b2017-01-06 12:34:14 -07007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
John Kessenich140f3df2015-06-26 16:58:36 -060010//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
John Kessenich927608b2017-01-06 12:34:14 -070023// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34// POSSIBILITY OF SUCH DAMAGE.
John Kessenich140f3df2015-06-26 16:58:36 -060035
36//
John Kessenich140f3df2015-06-26 16:58:36 -060037// Helper for making SPIR-V IR. Generally, this is documented in the header
38// SpvBuilder.h.
39//
40
John Kessenich66ec80e2016-08-05 14:04:23 -060041#include <cassert>
42#include <cstdlib>
John Kessenich140f3df2015-06-26 16:58:36 -060043
John Kessenich426394d2015-07-23 10:22:48 -060044#include <unordered_set>
qining1f2820a2016-04-14 18:34:27 -040045#include <algorithm>
John Kessenich426394d2015-07-23 10:22:48 -060046
John Kessenich140f3df2015-06-26 16:58:36 -060047#include "SpvBuilder.h"
48
John Kessenich66011cb2018-03-06 16:12:04 -070049#include "hex_float.h"
Rex Xuc9e3c3c2016-07-29 16:00:05 +080050
John Kessenich140f3df2015-06-26 16:58:36 -060051#ifndef _WIN32
52 #include <cstdio>
53#endif
54
55namespace spv {
56
John Kessenich2b5ea9f2018-01-31 18:35:56 -070057Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
58 spvVersion(spvVersion),
John Kessenich140f3df2015-06-26 16:58:36 -060059 source(SourceLanguageUnknown),
60 sourceVersion(0),
John Kessenich121853f2017-05-31 17:11:16 -060061 sourceFileStringId(NoResult),
John Kesseniche485c7a2017-05-31 18:50:53 -060062 currentLine(0),
63 emitOpLines(false),
John Kessenich140f3df2015-06-26 16:58:36 -060064 addressModel(AddressingModelLogical),
65 memoryModel(MemoryModelGLSL450),
John Kessenich55e7d112015-11-15 21:33:39 -070066 builderNumber(magicNumber),
John Kessenich140f3df2015-06-26 16:58:36 -060067 buildPoint(0),
68 uniqueId(0),
John Kessenich517fe7a2016-11-26 13:31:47 -070069 entryPointFunction(0),
Lei Zhang09caf122016-05-02 18:11:54 -040070 generatingOpCodeForSpecConst(false),
Lei Zhang17535f72016-05-04 15:55:59 -040071 logger(buildLogger)
John Kessenich140f3df2015-06-26 16:58:36 -060072{
73 clearAccessChain();
74}
75
76Builder::~Builder()
77{
78}
79
80Id Builder::import(const char* name)
81{
82 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
83 import->addStringOperand(name);
John Kessenich149afc32018-08-14 13:31:43 -060084 module.mapInstruction(import);
John Kessenichecba76f2017-01-06 00:34:48 -070085
Andrew Woloszynb7946d12016-01-18 09:23:56 -050086 imports.push_back(std::unique_ptr<Instruction>(import));
John Kessenich140f3df2015-06-26 16:58:36 -060087 return import->getResultId();
88}
89
John Kesseniche485c7a2017-05-31 18:50:53 -060090// Emit an OpLine if we've been asked to emit OpLines and the line number
91// has changed since the last time, and is a valid line number.
92void Builder::setLine(int lineNum)
93{
94 if (lineNum != 0 && lineNum != currentLine) {
95 currentLine = lineNum;
96 if (emitOpLines)
97 addLine(sourceFileStringId, currentLine, 0);
98 }
99}
100
101void Builder::addLine(Id fileName, int lineNum, int column)
102{
103 Instruction* line = new Instruction(OpLine);
104 line->addIdOperand(fileName);
105 line->addImmediateOperand(lineNum);
106 line->addImmediateOperand(column);
107 buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
108}
109
John Kessenich140f3df2015-06-26 16:58:36 -0600110// For creating new groupedTypes (will return old type if the requested one was already made).
111Id Builder::makeVoidType()
112{
113 Instruction* type;
114 if (groupedTypes[OpTypeVoid].size() == 0) {
115 type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
116 groupedTypes[OpTypeVoid].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500117 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600118 module.mapInstruction(type);
119 } else
120 type = groupedTypes[OpTypeVoid].back();
121
122 return type->getResultId();
123}
124
125Id Builder::makeBoolType()
126{
127 Instruction* type;
128 if (groupedTypes[OpTypeBool].size() == 0) {
129 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
130 groupedTypes[OpTypeBool].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500131 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600132 module.mapInstruction(type);
133 } else
134 type = groupedTypes[OpTypeBool].back();
135
136 return type->getResultId();
137}
138
John Kessenich55e7d112015-11-15 21:33:39 -0700139Id Builder::makeSamplerType()
140{
141 Instruction* type;
142 if (groupedTypes[OpTypeSampler].size() == 0) {
143 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
144 groupedTypes[OpTypeSampler].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500145 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich55e7d112015-11-15 21:33:39 -0700146 module.mapInstruction(type);
147 } else
148 type = groupedTypes[OpTypeSampler].back();
149
150 return type->getResultId();
151}
152
John Kessenich140f3df2015-06-26 16:58:36 -0600153Id Builder::makePointer(StorageClass storageClass, Id pointee)
154{
155 // try to find it
156 Instruction* type;
157 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
158 type = groupedTypes[OpTypePointer][t];
159 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
160 type->getIdOperand(1) == pointee)
161 return type->getResultId();
162 }
163
164 // not found, make it
165 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
166 type->addImmediateOperand(storageClass);
167 type->addIdOperand(pointee);
168 groupedTypes[OpTypePointer].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500169 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600170 module.mapInstruction(type);
171
172 return type->getResultId();
173}
174
175Id Builder::makeIntegerType(int width, bool hasSign)
176{
177 // try to find it
178 Instruction* type;
179 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
180 type = groupedTypes[OpTypeInt][t];
181 if (type->getImmediateOperand(0) == (unsigned)width &&
182 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
183 return type->getResultId();
184 }
185
186 // not found, make it
187 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
188 type->addImmediateOperand(width);
189 type->addImmediateOperand(hasSign ? 1 : 0);
190 groupedTypes[OpTypeInt].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500191 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600192 module.mapInstruction(type);
193
John Kessenich3c522072016-02-14 17:11:15 -0700194 // deal with capabilities
195 switch (width) {
John Kessenich66011cb2018-03-06 16:12:04 -0700196 case 8:
197 addCapability(CapabilityInt8);
198 break;
John Kessenich3c522072016-02-14 17:11:15 -0700199 case 16:
200 addCapability(CapabilityInt16);
201 break;
202 case 64:
203 addCapability(CapabilityInt64);
204 break;
205 default:
206 break;
207 }
208
John Kessenich140f3df2015-06-26 16:58:36 -0600209 return type->getResultId();
210}
211
212Id Builder::makeFloatType(int width)
213{
214 // try to find it
215 Instruction* type;
216 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
217 type = groupedTypes[OpTypeFloat][t];
218 if (type->getImmediateOperand(0) == (unsigned)width)
219 return type->getResultId();
220 }
221
222 // not found, make it
223 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
224 type->addImmediateOperand(width);
225 groupedTypes[OpTypeFloat].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500226 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600227 module.mapInstruction(type);
228
John Kessenich3c522072016-02-14 17:11:15 -0700229 // deal with capabilities
230 switch (width) {
231 case 16:
232 addCapability(CapabilityFloat16);
233 break;
234 case 64:
235 addCapability(CapabilityFloat64);
236 break;
237 default:
238 break;
239 }
240
John Kessenich140f3df2015-06-26 16:58:36 -0600241 return type->getResultId();
242}
243
John Kessenich55e7d112015-11-15 21:33:39 -0700244// Make a struct without checking for duplication.
245// See makeStructResultType() for non-decorated structs
246// needed as the result of some instructions, which does
247// check for duplicates.
John Kessenich32cfd492016-02-02 12:37:46 -0700248Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600249{
John Kessenich55e7d112015-11-15 21:33:39 -0700250 // Don't look for previous one, because in the general case,
251 // structs can be duplicated except for decorations.
252
John Kessenich140f3df2015-06-26 16:58:36 -0600253 // not found, make it
254 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
255 for (int op = 0; op < (int)members.size(); ++op)
256 type->addIdOperand(members[op]);
257 groupedTypes[OpTypeStruct].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500258 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600259 module.mapInstruction(type);
260 addName(type->getResultId(), name);
261
262 return type->getResultId();
263}
264
John Kessenich55e7d112015-11-15 21:33:39 -0700265// Make a struct for the simple results of several instructions,
266// checking for duplication.
267Id Builder::makeStructResultType(Id type0, Id type1)
268{
269 // try to find it
270 Instruction* type;
271 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
272 type = groupedTypes[OpTypeStruct][t];
273 if (type->getNumOperands() != 2)
274 continue;
John Kessenichecba76f2017-01-06 00:34:48 -0700275 if (type->getIdOperand(0) != type0 ||
John Kessenich55e7d112015-11-15 21:33:39 -0700276 type->getIdOperand(1) != type1)
277 continue;
278 return type->getResultId();
279 }
280
281 // not found, make it
282 std::vector<spv::Id> members;
283 members.push_back(type0);
284 members.push_back(type1);
285
286 return makeStructType(members, "ResType");
287}
288
John Kessenich140f3df2015-06-26 16:58:36 -0600289Id Builder::makeVectorType(Id component, int size)
290{
291 // try to find it
292 Instruction* type;
293 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
294 type = groupedTypes[OpTypeVector][t];
295 if (type->getIdOperand(0) == component &&
296 type->getImmediateOperand(1) == (unsigned)size)
297 return type->getResultId();
298 }
299
300 // not found, make it
301 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
302 type->addIdOperand(component);
303 type->addImmediateOperand(size);
304 groupedTypes[OpTypeVector].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500305 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600306 module.mapInstruction(type);
307
308 return type->getResultId();
309}
310
311Id Builder::makeMatrixType(Id component, int cols, int rows)
312{
313 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
314
315 Id column = makeVectorType(component, rows);
316
317 // try to find it
318 Instruction* type;
319 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
320 type = groupedTypes[OpTypeMatrix][t];
321 if (type->getIdOperand(0) == column &&
322 type->getImmediateOperand(1) == (unsigned)cols)
323 return type->getResultId();
324 }
325
326 // not found, make it
327 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
328 type->addIdOperand(column);
329 type->addImmediateOperand(cols);
330 groupedTypes[OpTypeMatrix].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500331 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600332 module.mapInstruction(type);
333
334 return type->getResultId();
335}
336
John Kessenichc9e0a422015-12-29 21:27:24 -0700337// TODO: performance: track arrays per stride
338// If a stride is supplied (non-zero) make an array.
339// If no stride (0), reuse previous array types.
John Kessenich6c292d32016-02-15 20:58:50 -0700340// 'size' is an Id of a constant or specialization constant of the array size
341Id Builder::makeArrayType(Id element, Id sizeId, int stride)
John Kessenich140f3df2015-06-26 16:58:36 -0600342{
John Kessenich140f3df2015-06-26 16:58:36 -0600343 Instruction* type;
John Kessenichc9e0a422015-12-29 21:27:24 -0700344 if (stride == 0) {
345 // try to find existing type
346 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
347 type = groupedTypes[OpTypeArray][t];
348 if (type->getIdOperand(0) == element &&
349 type->getIdOperand(1) == sizeId)
350 return type->getResultId();
351 }
John Kessenich140f3df2015-06-26 16:58:36 -0600352 }
353
354 // not found, make it
355 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
356 type->addIdOperand(element);
357 type->addIdOperand(sizeId);
358 groupedTypes[OpTypeArray].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500359 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600360 module.mapInstruction(type);
361
362 return type->getResultId();
363}
364
John Kessenichc9a80832015-09-12 12:17:44 -0600365Id Builder::makeRuntimeArray(Id element)
366{
367 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
368 type->addIdOperand(element);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500369 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenichc9a80832015-09-12 12:17:44 -0600370 module.mapInstruction(type);
371
372 return type->getResultId();
373}
374
John Kessenich32cfd492016-02-02 12:37:46 -0700375Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
John Kessenich140f3df2015-06-26 16:58:36 -0600376{
377 // try to find it
378 Instruction* type;
379 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
380 type = groupedTypes[OpTypeFunction][t];
381 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
382 continue;
383 bool mismatch = false;
384 for (int p = 0; p < (int)paramTypes.size(); ++p) {
385 if (paramTypes[p] != type->getIdOperand(p + 1)) {
386 mismatch = true;
387 break;
388 }
389 }
390 if (! mismatch)
John Kessenichc9a80832015-09-12 12:17:44 -0600391 return type->getResultId();
John Kessenich140f3df2015-06-26 16:58:36 -0600392 }
393
394 // not found, make it
395 type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
396 type->addIdOperand(returnType);
397 for (int p = 0; p < (int)paramTypes.size(); ++p)
398 type->addIdOperand(paramTypes[p]);
399 groupedTypes[OpTypeFunction].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500400 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600401 module.mapInstruction(type);
402
403 return type->getResultId();
404}
405
John Kessenich5e4b1242015-08-06 22:53:06 -0600406Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
John Kessenich140f3df2015-06-26 16:58:36 -0600407{
John Kessenich260f5062017-08-14 22:10:00 -0600408 assert(sampled == 1 || sampled == 2);
409
John Kessenich140f3df2015-06-26 16:58:36 -0600410 // try to find it
411 Instruction* type;
John Kessenich5e4b1242015-08-06 22:53:06 -0600412 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
413 type = groupedTypes[OpTypeImage][t];
John Kessenich140f3df2015-06-26 16:58:36 -0600414 if (type->getIdOperand(0) == sampledType &&
415 type->getImmediateOperand(1) == (unsigned int)dim &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600416 type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
John Kessenich140f3df2015-06-26 16:58:36 -0600417 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600418 type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
419 type->getImmediateOperand(5) == sampled &&
420 type->getImmediateOperand(6) == (unsigned int)format)
John Kessenich140f3df2015-06-26 16:58:36 -0600421 return type->getResultId();
422 }
423
424 // not found, make it
John Kessenich5e4b1242015-08-06 22:53:06 -0600425 type = new Instruction(getUniqueId(), NoType, OpTypeImage);
John Kessenich140f3df2015-06-26 16:58:36 -0600426 type->addIdOperand(sampledType);
427 type->addImmediateOperand( dim);
John Kessenich5e4b1242015-08-06 22:53:06 -0600428 type->addImmediateOperand( depth ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600429 type->addImmediateOperand(arrayed ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600430 type->addImmediateOperand( ms ? 1 : 0);
John Kessenich5e4b1242015-08-06 22:53:06 -0600431 type->addImmediateOperand(sampled);
432 type->addImmediateOperand((unsigned int)format);
John Kessenich140f3df2015-06-26 16:58:36 -0600433
John Kessenich5e4b1242015-08-06 22:53:06 -0600434 groupedTypes[OpTypeImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500435 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich5e4b1242015-08-06 22:53:06 -0600436 module.mapInstruction(type);
437
John Kessenichb0364dc2016-02-14 17:37:30 -0700438 // deal with capabilities
439 switch (dim) {
440 case DimBuffer:
John Kessenich260f5062017-08-14 22:10:00 -0600441 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700442 addCapability(CapabilitySampledBuffer);
443 else
444 addCapability(CapabilityImageBuffer);
445 break;
446 case Dim1D:
John Kessenich260f5062017-08-14 22:10:00 -0600447 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700448 addCapability(CapabilitySampled1D);
449 else
450 addCapability(CapabilityImage1D);
451 break;
452 case DimCube:
453 if (arrayed) {
John Kessenich260f5062017-08-14 22:10:00 -0600454 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700455 addCapability(CapabilitySampledCubeArray);
456 else
457 addCapability(CapabilityImageCubeArray);
458 }
459 break;
460 case DimRect:
John Kessenich260f5062017-08-14 22:10:00 -0600461 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700462 addCapability(CapabilitySampledRect);
463 else
464 addCapability(CapabilityImageRect);
465 break;
466 case DimSubpassData:
467 addCapability(CapabilityInputAttachment);
468 break;
469 default:
470 break;
471 }
472
473 if (ms) {
John Kessenich260f5062017-08-14 22:10:00 -0600474 if (sampled == 2) {
John Kessenich7a9db712017-10-20 10:56:50 -0600475 // Images used with subpass data are not storage
476 // images, so don't require the capability for them.
477 if (dim != Dim::DimSubpassData)
478 addCapability(CapabilityStorageImageMultisample);
John Kessenich260f5062017-08-14 22:10:00 -0600479 if (arrayed)
480 addCapability(CapabilityImageMSArray);
481 }
John Kessenichb0364dc2016-02-14 17:37:30 -0700482 }
483
John Kessenich5e4b1242015-08-06 22:53:06 -0600484 return type->getResultId();
485}
486
487Id Builder::makeSampledImageType(Id imageType)
488{
489 // try to find it
490 Instruction* type;
491 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
492 type = groupedTypes[OpTypeSampledImage][t];
493 if (type->getIdOperand(0) == imageType)
494 return type->getResultId();
495 }
496
497 // not found, make it
498 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
499 type->addIdOperand(imageType);
500
501 groupedTypes[OpTypeSampledImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500502 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600503 module.mapInstruction(type);
504
505 return type->getResultId();
506}
507
508Id Builder::getDerefTypeId(Id resultId) const
509{
510 Id typeId = getTypeId(resultId);
511 assert(isPointerType(typeId));
512
John Kessenich228e9642018-08-13 21:37:59 -0600513 return module.getInstruction(typeId)->getIdOperand(1);
John Kessenich140f3df2015-06-26 16:58:36 -0600514}
515
516Op Builder::getMostBasicTypeClass(Id typeId) const
517{
518 Instruction* instr = module.getInstruction(typeId);
519
520 Op typeClass = instr->getOpCode();
521 switch (typeClass)
522 {
523 case OpTypeVoid:
524 case OpTypeBool:
525 case OpTypeInt:
526 case OpTypeFloat:
527 case OpTypeStruct:
528 return typeClass;
529 case OpTypeVector:
530 case OpTypeMatrix:
531 case OpTypeArray:
532 case OpTypeRuntimeArray:
533 return getMostBasicTypeClass(instr->getIdOperand(0));
534 case OpTypePointer:
535 return getMostBasicTypeClass(instr->getIdOperand(1));
536 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700537 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600538 return OpTypeFloat;
539 }
540}
541
John Kessenich22118352015-12-21 20:54:09 -0700542int Builder::getNumTypeConstituents(Id typeId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600543{
544 Instruction* instr = module.getInstruction(typeId);
545
546 switch (instr->getOpCode())
547 {
548 case OpTypeBool:
549 case OpTypeInt:
550 case OpTypeFloat:
551 return 1;
552 case OpTypeVector:
553 case OpTypeMatrix:
554 return instr->getImmediateOperand(1);
John Kessenich6c292d32016-02-15 20:58:50 -0700555 case OpTypeArray:
556 {
John Kessenich228e9642018-08-13 21:37:59 -0600557 Id lengthId = instr->getIdOperand(1);
John Kessenich6c292d32016-02-15 20:58:50 -0700558 return module.getInstruction(lengthId)->getImmediateOperand(0);
559 }
John Kessenich22118352015-12-21 20:54:09 -0700560 case OpTypeStruct:
561 return instr->getNumOperands();
John Kessenich140f3df2015-06-26 16:58:36 -0600562 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700563 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600564 return 1;
565 }
566}
567
568// Return the lowest-level type of scalar that an homogeneous composite is made out of.
569// Typically, this is just to find out if something is made out of ints or floats.
570// However, it includes returning a structure, if say, it is an array of structure.
571Id Builder::getScalarTypeId(Id typeId) const
572{
573 Instruction* instr = module.getInstruction(typeId);
574
575 Op typeClass = instr->getOpCode();
576 switch (typeClass)
577 {
578 case OpTypeVoid:
579 case OpTypeBool:
580 case OpTypeInt:
581 case OpTypeFloat:
582 case OpTypeStruct:
583 return instr->getResultId();
584 case OpTypeVector:
585 case OpTypeMatrix:
586 case OpTypeArray:
587 case OpTypeRuntimeArray:
588 case OpTypePointer:
589 return getScalarTypeId(getContainedTypeId(typeId));
590 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700591 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600592 return NoResult;
593 }
594}
595
596// Return the type of 'member' of a composite.
597Id Builder::getContainedTypeId(Id typeId, int member) const
598{
599 Instruction* instr = module.getInstruction(typeId);
600
601 Op typeClass = instr->getOpCode();
602 switch (typeClass)
603 {
604 case OpTypeVector:
605 case OpTypeMatrix:
606 case OpTypeArray:
607 case OpTypeRuntimeArray:
608 return instr->getIdOperand(0);
609 case OpTypePointer:
610 return instr->getIdOperand(1);
611 case OpTypeStruct:
612 return instr->getIdOperand(member);
613 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700614 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600615 return NoResult;
616 }
617}
618
619// Return the immediately contained type of a given composite type.
620Id Builder::getContainedTypeId(Id typeId) const
621{
622 return getContainedTypeId(typeId, 0);
623}
624
625// See if a scalar constant of this type has already been created, so it
626// can be reused rather than duplicated. (Required by the specification).
John Kessenich46413d52018-02-26 19:20:05 -0700627Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
John Kessenich140f3df2015-06-26 16:58:36 -0600628{
629 Instruction* constant;
630 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
631 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700632 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600633 constant->getTypeId() == typeId &&
634 constant->getImmediateOperand(0) == value)
635 return constant->getResultId();
636 }
637
638 return 0;
639}
640
Rex Xu8ff43de2016-04-22 16:51:45 +0800641// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
John Kessenich46413d52018-02-26 19:20:05 -0700642Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2)
John Kessenich140f3df2015-06-26 16:58:36 -0600643{
644 Instruction* constant;
645 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
646 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700647 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600648 constant->getTypeId() == typeId &&
649 constant->getImmediateOperand(0) == v1 &&
650 constant->getImmediateOperand(1) == v2)
651 return constant->getResultId();
652 }
653
654 return 0;
655}
656
John Kessenichf685df82015-10-13 10:55:08 -0600657// Return true if consuming 'opcode' means consuming a constant.
658// "constant" here means after final transform to executable code,
659// the value consumed will be a constant, so includes specialization.
John Kessenich71631272015-10-13 10:39:19 -0600660bool Builder::isConstantOpCode(Op opcode) const
661{
662 switch (opcode) {
John Kessenichecba76f2017-01-06 00:34:48 -0700663 case OpUndef:
John Kessenich71631272015-10-13 10:39:19 -0600664 case OpConstantTrue:
665 case OpConstantFalse:
666 case OpConstant:
667 case OpConstantComposite:
668 case OpConstantSampler:
669 case OpConstantNull:
670 case OpSpecConstantTrue:
671 case OpSpecConstantFalse:
672 case OpSpecConstant:
673 case OpSpecConstantComposite:
674 case OpSpecConstantOp:
675 return true;
676 default:
677 return false;
678 }
679}
680
qining27e04a02016-04-14 16:40:20 -0400681// Return true if consuming 'opcode' means consuming a specialization constant.
682bool Builder::isSpecConstantOpCode(Op opcode) const
683{
684 switch (opcode) {
685 case OpSpecConstantTrue:
686 case OpSpecConstantFalse:
687 case OpSpecConstant:
688 case OpSpecConstantComposite:
689 case OpSpecConstantOp:
690 return true;
691 default:
692 return false;
693 }
694}
695
John Kessenich55e7d112015-11-15 21:33:39 -0700696Id Builder::makeBoolConstant(bool b, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600697{
698 Id typeId = makeBoolType();
699 Instruction* constant;
John Kessenich55e7d112015-11-15 21:33:39 -0700700 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
John Kessenich140f3df2015-06-26 16:58:36 -0600701
John Kessenich6c292d32016-02-15 20:58:50 -0700702 // See if we already made it. Applies only to regular constants, because specialization constants
703 // must remain distinct for the purpose of applying a SpecId decoration.
704 if (! specConstant) {
705 Id existing = 0;
706 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
707 constant = groupedConstants[OpTypeBool][i];
708 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
709 existing = constant->getResultId();
710 }
John Kessenich140f3df2015-06-26 16:58:36 -0600711
John Kessenich6c292d32016-02-15 20:58:50 -0700712 if (existing)
713 return existing;
714 }
John Kessenich140f3df2015-06-26 16:58:36 -0600715
716 // Make it
John Kessenich55e7d112015-11-15 21:33:39 -0700717 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500718 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600719 groupedConstants[OpTypeBool].push_back(c);
720 module.mapInstruction(c);
721
722 return c->getResultId();
723}
724
John Kessenich55e7d112015-11-15 21:33:39 -0700725Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600726{
John Kessenich55e7d112015-11-15 21:33:39 -0700727 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich6c292d32016-02-15 20:58:50 -0700728
729 // See if we already made it. Applies only to regular constants, because specialization constants
730 // must remain distinct for the purpose of applying a SpecId decoration.
731 if (! specConstant) {
732 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
733 if (existing)
734 return existing;
735 }
John Kessenich140f3df2015-06-26 16:58:36 -0600736
John Kessenich55e7d112015-11-15 21:33:39 -0700737 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600738 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500739 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600740 groupedConstants[OpTypeInt].push_back(c);
741 module.mapInstruction(c);
742
743 return c->getResultId();
744}
745
Rex Xu8ff43de2016-04-22 16:51:45 +0800746Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
747{
748 Op opcode = specConstant ? OpSpecConstant : OpConstant;
749
750 unsigned op1 = value & 0xFFFFFFFF;
751 unsigned op2 = value >> 32;
752
753 // See if we already made it. Applies only to regular constants, because specialization constants
754 // must remain distinct for the purpose of applying a SpecId decoration.
755 if (! specConstant) {
756 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
757 if (existing)
758 return existing;
759 }
760
761 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
762 c->addImmediateOperand(op1);
763 c->addImmediateOperand(op2);
764 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
765 groupedConstants[OpTypeInt].push_back(c);
766 module.mapInstruction(c);
767
768 return c->getResultId();
769}
770
John Kessenich55e7d112015-11-15 21:33:39 -0700771Id Builder::makeFloatConstant(float f, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600772{
John Kessenich55e7d112015-11-15 21:33:39 -0700773 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600774 Id typeId = makeFloatType(32);
Mark Adams18b637f2016-02-23 12:17:11 -0500775 union { float fl; unsigned int ui; } u;
776 u.fl = f;
777 unsigned value = u.ui;
John Kessenich6c292d32016-02-15 20:58:50 -0700778
779 // See if we already made it. Applies only to regular constants, because specialization constants
780 // must remain distinct for the purpose of applying a SpecId decoration.
781 if (! specConstant) {
782 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
783 if (existing)
784 return existing;
785 }
John Kessenich140f3df2015-06-26 16:58:36 -0600786
John Kessenich55e7d112015-11-15 21:33:39 -0700787 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600788 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500789 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600790 groupedConstants[OpTypeFloat].push_back(c);
791 module.mapInstruction(c);
792
793 return c->getResultId();
794}
795
John Kessenich55e7d112015-11-15 21:33:39 -0700796Id Builder::makeDoubleConstant(double d, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600797{
John Kessenich55e7d112015-11-15 21:33:39 -0700798 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600799 Id typeId = makeFloatType(64);
Mark Adams18b637f2016-02-23 12:17:11 -0500800 union { double db; unsigned long long ull; } u;
801 u.db = d;
802 unsigned long long value = u.ull;
John Kessenich140f3df2015-06-26 16:58:36 -0600803 unsigned op1 = value & 0xFFFFFFFF;
804 unsigned op2 = value >> 32;
John Kessenich6c292d32016-02-15 20:58:50 -0700805
806 // See if we already made it. Applies only to regular constants, because specialization constants
807 // must remain distinct for the purpose of applying a SpecId decoration.
808 if (! specConstant) {
809 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
810 if (existing)
811 return existing;
812 }
John Kessenich140f3df2015-06-26 16:58:36 -0600813
John Kessenich55e7d112015-11-15 21:33:39 -0700814 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600815 c->addImmediateOperand(op1);
816 c->addImmediateOperand(op2);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500817 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600818 groupedConstants[OpTypeFloat].push_back(c);
819 module.mapInstruction(c);
820
821 return c->getResultId();
822}
823
Rex Xuc9e3c3c2016-07-29 16:00:05 +0800824Id Builder::makeFloat16Constant(float f16, bool specConstant)
825{
826 Op opcode = specConstant ? OpSpecConstant : OpConstant;
827 Id typeId = makeFloatType(16);
828
829 spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
830 spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
baldurk033d3ef2016-10-13 19:28:20 +0200831 fVal.castTo(f16Val, spvutils::kRoundToZero);
Rex Xuc9e3c3c2016-07-29 16:00:05 +0800832
833 unsigned value = f16Val.value().getAsFloat().get_value();
834
835 // See if we already made it. Applies only to regular constants, because specialization constants
836 // must remain distinct for the purpose of applying a SpecId decoration.
837 if (!specConstant) {
838 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
839 if (existing)
840 return existing;
841 }
842
843 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
844 c->addImmediateOperand(value);
845 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
846 groupedConstants[OpTypeFloat].push_back(c);
847 module.mapInstruction(c);
848
849 return c->getResultId();
850}
Rex Xuc9e3c3c2016-07-29 16:00:05 +0800851
Neil Robertseddb1312018-03-13 10:57:59 +0100852Id Builder::makeFpConstant(Id type, double d, bool specConstant)
853{
854 assert(isFloatType(type));
855
856 switch (getScalarTypeWidth(type)) {
857 case 16:
John Kessenichead86222018-03-28 18:01:20 -0600858 return makeFloat16Constant((float)d, specConstant);
Neil Robertseddb1312018-03-13 10:57:59 +0100859 case 32:
John Kessenichead86222018-03-28 18:01:20 -0600860 return makeFloatConstant((float)d, specConstant);
Neil Robertseddb1312018-03-13 10:57:59 +0100861 case 64:
862 return makeDoubleConstant(d, specConstant);
John Kessenich97e35422018-03-22 23:44:11 -0600863 default:
864 break;
Neil Robertseddb1312018-03-13 10:57:59 +0100865 }
866
867 assert(false);
John Kessenich97e35422018-03-22 23:44:11 -0600868 return NoResult;
Neil Robertseddb1312018-03-13 10:57:59 +0100869}
870
John Kessenich46413d52018-02-26 19:20:05 -0700871Id Builder::findCompositeConstant(Op typeClass, const std::vector<Id>& comps)
John Kessenich140f3df2015-06-26 16:58:36 -0600872{
873 Instruction* constant = 0;
874 bool found = false;
875 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
876 constant = groupedConstants[typeClass][i];
877
878 // same shape?
879 if (constant->getNumOperands() != (int)comps.size())
880 continue;
881
882 // same contents?
883 bool mismatch = false;
884 for (int op = 0; op < constant->getNumOperands(); ++op) {
885 if (constant->getIdOperand(op) != comps[op]) {
886 mismatch = true;
887 break;
888 }
889 }
890 if (! mismatch) {
891 found = true;
892 break;
893 }
894 }
895
896 return found ? constant->getResultId() : NoResult;
897}
898
John Kessenich46413d52018-02-26 19:20:05 -0700899Id Builder::findStructConstant(Id typeId, const std::vector<Id>& comps)
900{
901 Instruction* constant = 0;
902 bool found = false;
903 for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) {
904 constant = groupedStructConstants[typeId][i];
905
906 // same contents?
907 bool mismatch = false;
908 for (int op = 0; op < constant->getNumOperands(); ++op) {
909 if (constant->getIdOperand(op) != comps[op]) {
910 mismatch = true;
911 break;
912 }
913 }
914 if (! mismatch) {
915 found = true;
916 break;
917 }
918 }
919
920 return found ? constant->getResultId() : NoResult;
921}
922
John Kessenich140f3df2015-06-26 16:58:36 -0600923// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +0300924Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600925{
John Kessenich6c292d32016-02-15 20:58:50 -0700926 Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
John Kessenich140f3df2015-06-26 16:58:36 -0600927 assert(typeId);
928 Op typeClass = getTypeClass(typeId);
929
930 switch (typeClass) {
931 case OpTypeVector:
932 case OpTypeArray:
John Kessenich140f3df2015-06-26 16:58:36 -0600933 case OpTypeMatrix:
John Kessenich46413d52018-02-26 19:20:05 -0700934 if (! specConstant) {
935 Id existing = findCompositeConstant(typeClass, members);
936 if (existing)
937 return existing;
938 }
939 break;
940 case OpTypeStruct:
941 if (! specConstant) {
942 Id existing = findStructConstant(typeId, members);
943 if (existing)
944 return existing;
945 }
John Kessenich140f3df2015-06-26 16:58:36 -0600946 break;
947 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700948 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600949 return makeFloatConstant(0.0);
950 }
951
John Kessenich6c292d32016-02-15 20:58:50 -0700952 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600953 for (int op = 0; op < (int)members.size(); ++op)
954 c->addIdOperand(members[op]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500955 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich46413d52018-02-26 19:20:05 -0700956 if (typeClass == OpTypeStruct)
957 groupedStructConstants[typeId].push_back(c);
958 else
959 groupedConstants[typeClass].push_back(c);
John Kessenich140f3df2015-06-26 16:58:36 -0600960 module.mapInstruction(c);
961
962 return c->getResultId();
963}
964
John Kessenich55e7d112015-11-15 21:33:39 -0700965Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600966{
967 Instruction* entryPoint = new Instruction(OpEntryPoint);
968 entryPoint->addImmediateOperand(model);
969 entryPoint->addIdOperand(function->getId());
John Kessenich5e4b1242015-08-06 22:53:06 -0600970 entryPoint->addStringOperand(name);
John Kessenich140f3df2015-06-26 16:58:36 -0600971
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500972 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
John Kessenich55e7d112015-11-15 21:33:39 -0700973
974 return entryPoint;
John Kessenich140f3df2015-06-26 16:58:36 -0600975}
976
John Kessenichb56a26a2015-09-16 16:04:05 -0600977// Currently relying on the fact that all 'value' of interest are small non-negative values.
978void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
John Kessenich140f3df2015-06-26 16:58:36 -0600979{
John Kessenich140f3df2015-06-26 16:58:36 -0600980 Instruction* instr = new Instruction(OpExecutionMode);
981 instr->addIdOperand(entryPoint->getId());
982 instr->addImmediateOperand(mode);
John Kessenichb56a26a2015-09-16 16:04:05 -0600983 if (value1 >= 0)
984 instr->addImmediateOperand(value1);
985 if (value2 >= 0)
986 instr->addImmediateOperand(value2);
987 if (value3 >= 0)
988 instr->addImmediateOperand(value3);
John Kessenich140f3df2015-06-26 16:58:36 -0600989
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500990 executionModes.push_back(std::unique_ptr<Instruction>(instr));
John Kessenich140f3df2015-06-26 16:58:36 -0600991}
992
993void Builder::addName(Id id, const char* string)
994{
995 Instruction* name = new Instruction(OpName);
996 name->addIdOperand(id);
997 name->addStringOperand(string);
998
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500999 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -06001000}
1001
1002void Builder::addMemberName(Id id, int memberNumber, const char* string)
1003{
1004 Instruction* name = new Instruction(OpMemberName);
1005 name->addIdOperand(id);
1006 name->addImmediateOperand(memberNumber);
1007 name->addStringOperand(string);
1008
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001009 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -06001010}
1011
John Kessenich140f3df2015-06-26 16:58:36 -06001012void Builder::addDecoration(Id id, Decoration decoration, int num)
1013{
John Kessenich4016e382016-07-15 11:53:56 -06001014 if (decoration == spv::DecorationMax)
John Kessenich55e7d112015-11-15 21:33:39 -07001015 return;
John Kessenich5d610ee2018-03-07 18:05:55 -07001016
John Kessenich140f3df2015-06-26 16:58:36 -06001017 Instruction* dec = new Instruction(OpDecorate);
1018 dec->addIdOperand(id);
1019 dec->addImmediateOperand(decoration);
1020 if (num >= 0)
1021 dec->addImmediateOperand(num);
1022
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001023 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -06001024}
1025
John Kessenich5d610ee2018-03-07 18:05:55 -07001026void Builder::addDecoration(Id id, Decoration decoration, const char* s)
1027{
1028 if (decoration == spv::DecorationMax)
1029 return;
1030
1031 Instruction* dec = new Instruction(OpDecorateStringGOOGLE);
1032 dec->addIdOperand(id);
1033 dec->addImmediateOperand(decoration);
1034 dec->addStringOperand(s);
1035
1036 decorations.push_back(std::unique_ptr<Instruction>(dec));
1037}
1038
1039void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
1040{
1041 if (decoration == spv::DecorationMax)
1042 return;
1043
1044 Instruction* dec = new Instruction(OpDecorateId);
1045 dec->addIdOperand(id);
1046 dec->addImmediateOperand(decoration);
1047 dec->addIdOperand(idDecoration);
1048
1049 decorations.push_back(std::unique_ptr<Instruction>(dec));
1050}
1051
John Kessenich140f3df2015-06-26 16:58:36 -06001052void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
1053{
John Kessenich5d610ee2018-03-07 18:05:55 -07001054 if (decoration == spv::DecorationMax)
1055 return;
1056
John Kessenich140f3df2015-06-26 16:58:36 -06001057 Instruction* dec = new Instruction(OpMemberDecorate);
1058 dec->addIdOperand(id);
1059 dec->addImmediateOperand(member);
1060 dec->addImmediateOperand(decoration);
1061 if (num >= 0)
1062 dec->addImmediateOperand(num);
1063
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001064 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -06001065}
1066
John Kessenich5d610ee2018-03-07 18:05:55 -07001067void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s)
1068{
1069 if (decoration == spv::DecorationMax)
1070 return;
1071
1072 Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE);
1073 dec->addIdOperand(id);
1074 dec->addImmediateOperand(member);
1075 dec->addImmediateOperand(decoration);
1076 dec->addStringOperand(s);
1077
1078 decorations.push_back(std::unique_ptr<Instruction>(dec));
1079}
1080
John Kessenich140f3df2015-06-26 16:58:36 -06001081// Comments in header
John Kessenich6fccb3c2016-09-19 16:01:41 -06001082Function* Builder::makeEntryPoint(const char* entryPoint)
John Kessenich140f3df2015-06-26 16:58:36 -06001083{
John Kessenich517fe7a2016-11-26 13:31:47 -07001084 assert(! entryPointFunction);
John Kessenich140f3df2015-06-26 16:58:36 -06001085
1086 Block* entry;
1087 std::vector<Id> params;
John Kessenichfad62972017-07-18 02:35:46 -06001088 std::vector<std::vector<Decoration>> decorations;
John Kessenich140f3df2015-06-26 16:58:36 -06001089
John Kessenichfad62972017-07-18 02:35:46 -06001090 entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
John Kessenich140f3df2015-06-26 16:58:36 -06001091
John Kessenich517fe7a2016-11-26 13:31:47 -07001092 return entryPointFunction;
John Kessenich140f3df2015-06-26 16:58:36 -06001093}
1094
1095// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001096Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
John Kessenichfad62972017-07-18 02:35:46 -06001097 const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry)
John Kessenich140f3df2015-06-26 16:58:36 -06001098{
John Kessenich32cfd492016-02-02 12:37:46 -07001099 // Make the function and initial instructions in it
John Kessenich140f3df2015-06-26 16:58:36 -06001100 Id typeId = makeFunctionType(returnType, paramTypes);
baldurkd76692d2015-07-12 11:32:58 +02001101 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
John Kessenich140f3df2015-06-26 16:58:36 -06001102 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
1103
John Kessenich32cfd492016-02-02 12:37:46 -07001104 // Set up the precisions
1105 setPrecision(function->getId(), precision);
John Kessenichfad62972017-07-18 02:35:46 -06001106 for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
1107 for (int d = 0; d < (int)decorations[p].size(); ++d)
1108 addDecoration(firstParamId + p, decorations[p][d]);
1109 }
John Kessenich32cfd492016-02-02 12:37:46 -07001110
1111 // CFG
John Kessenich140f3df2015-06-26 16:58:36 -06001112 if (entry) {
1113 *entry = new Block(getUniqueId(), *function);
1114 function->addBlock(*entry);
1115 setBuildPoint(*entry);
1116 }
1117
1118 if (name)
1119 addName(function->getId(), name);
1120
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001121 functions.push_back(std::unique_ptr<Function>(function));
1122
John Kessenich140f3df2015-06-26 16:58:36 -06001123 return function;
1124}
1125
1126// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -06001127void Builder::makeReturn(bool implicit, Id retVal)
John Kessenich140f3df2015-06-26 16:58:36 -06001128{
John Kesseniche770b3e2015-09-14 20:58:02 -06001129 if (retVal) {
John Kessenich140f3df2015-06-26 16:58:36 -06001130 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
1131 inst->addIdOperand(retVal);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001132 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -06001133 } else
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001134 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
John Kessenich140f3df2015-06-26 16:58:36 -06001135
1136 if (! implicit)
1137 createAndSetNoPredecessorBlock("post-return");
1138}
1139
1140// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -06001141void Builder::leaveFunction()
John Kessenich140f3df2015-06-26 16:58:36 -06001142{
1143 Block* block = buildPoint;
1144 Function& function = buildPoint->getParent();
1145 assert(block);
1146
1147 // If our function did not contain a return, add a return void now.
1148 if (! block->isTerminated()) {
Dejan Mircevskied55bcd2016-01-19 21:13:38 -05001149 if (function.getReturnType() == makeVoidType())
1150 makeReturn(true);
1151 else {
1152 makeReturn(true, createUndefined(function.getReturnType()));
John Kessenich140f3df2015-06-26 16:58:36 -06001153 }
1154 }
John Kessenich140f3df2015-06-26 16:58:36 -06001155}
1156
1157// Comments in header
1158void Builder::makeDiscard()
1159{
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001160 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
John Kessenich140f3df2015-06-26 16:58:36 -06001161 createAndSetNoPredecessorBlock("post-discard");
1162}
1163
1164// Comments in header
1165Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
1166{
1167 Id pointerType = makePointer(storageClass, type);
1168 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
1169 inst->addImmediateOperand(storageClass);
1170
1171 switch (storageClass) {
John Kessenich140f3df2015-06-26 16:58:36 -06001172 case StorageClassFunction:
1173 // Validation rules require the declaration in the entry block
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001174 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -06001175 break;
1176
1177 default:
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001178 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
John Kessenich55e7d112015-11-15 21:33:39 -07001179 module.mapInstruction(inst);
John Kessenich140f3df2015-06-26 16:58:36 -06001180 break;
1181 }
1182
1183 if (name)
1184 addName(inst->getResultId(), name);
1185
1186 return inst->getResultId();
1187}
1188
1189// Comments in header
Miro Knejp28f9b1c2015-08-11 02:45:24 +02001190Id Builder::createUndefined(Id type)
1191{
1192 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001193 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
Miro Knejp28f9b1c2015-08-11 02:45:24 +02001194 return inst->getResultId();
1195}
1196
1197// Comments in header
John Kessenich140f3df2015-06-26 16:58:36 -06001198void Builder::createStore(Id rValue, Id lValue)
1199{
1200 Instruction* store = new Instruction(OpStore);
1201 store->addIdOperand(lValue);
1202 store->addIdOperand(rValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001203 buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
John Kessenich140f3df2015-06-26 16:58:36 -06001204}
1205
1206// Comments in header
1207Id Builder::createLoad(Id lValue)
1208{
1209 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
1210 load->addIdOperand(lValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001211 buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
John Kessenich140f3df2015-06-26 16:58:36 -06001212
1213 return load->getResultId();
1214}
1215
1216// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001217Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
John Kessenich140f3df2015-06-26 16:58:36 -06001218{
1219 // Figure out the final resulting type.
1220 spv::Id typeId = getTypeId(base);
1221 assert(isPointerType(typeId) && offsets.size() > 0);
1222 typeId = getContainedTypeId(typeId);
1223 for (int i = 0; i < (int)offsets.size(); ++i) {
1224 if (isStructType(typeId)) {
1225 assert(isConstantScalar(offsets[i]));
1226 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
1227 } else
1228 typeId = getContainedTypeId(typeId, offsets[i]);
1229 }
1230 typeId = makePointer(storageClass, typeId);
1231
1232 // Make the instruction
1233 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
1234 chain->addIdOperand(base);
1235 for (int i = 0; i < (int)offsets.size(); ++i)
1236 chain->addIdOperand(offsets[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001237 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
John Kessenich140f3df2015-06-26 16:58:36 -06001238
1239 return chain->getResultId();
1240}
1241
John Kessenichee21fc92015-09-21 21:50:29 -06001242Id Builder::createArrayLength(Id base, unsigned int member)
1243{
John Kessenichac370792018-03-07 11:24:50 -07001244 spv::Id intType = makeIntType(32);
steve-lunarg5da1f032017-02-12 17:50:28 -07001245 Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength);
John Kessenichee21fc92015-09-21 21:50:29 -06001246 length->addIdOperand(base);
1247 length->addImmediateOperand(member);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001248 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
John Kessenichee21fc92015-09-21 21:50:29 -06001249
1250 return length->getResultId();
1251}
1252
John Kessenich140f3df2015-06-26 16:58:36 -06001253Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
1254{
qining13545202016-03-21 09:51:37 -04001255 // Generate code for spec constants if in spec constant operation
1256 // generation mode.
1257 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001258 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index));
qining13545202016-03-21 09:51:37 -04001259 }
John Kessenich140f3df2015-06-26 16:58:36 -06001260 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1261 extract->addIdOperand(composite);
1262 extract->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001263 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001264
1265 return extract->getResultId();
1266}
1267
Vlad Ivanov689490f2017-01-26 20:46:02 +03001268Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
John Kessenich140f3df2015-06-26 16:58:36 -06001269{
qining13545202016-03-21 09:51:37 -04001270 // Generate code for spec constants if in spec constant operation
1271 // generation mode.
1272 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001273 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
qining13545202016-03-21 09:51:37 -04001274 }
John Kessenich140f3df2015-06-26 16:58:36 -06001275 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1276 extract->addIdOperand(composite);
1277 for (int i = 0; i < (int)indexes.size(); ++i)
1278 extract->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001279 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001280
1281 return extract->getResultId();
1282}
1283
1284Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
1285{
1286 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1287 insert->addIdOperand(object);
1288 insert->addIdOperand(composite);
1289 insert->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001290 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001291
1292 return insert->getResultId();
1293}
1294
Vlad Ivanov689490f2017-01-26 20:46:02 +03001295Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
John Kessenich140f3df2015-06-26 16:58:36 -06001296{
1297 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1298 insert->addIdOperand(object);
1299 insert->addIdOperand(composite);
1300 for (int i = 0; i < (int)indexes.size(); ++i)
1301 insert->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001302 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001303
1304 return insert->getResultId();
1305}
1306
1307Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
1308{
1309 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
1310 extract->addIdOperand(vector);
1311 extract->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001312 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001313
1314 return extract->getResultId();
1315}
1316
1317Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
1318{
1319 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
1320 insert->addIdOperand(vector);
1321 insert->addIdOperand(component);
1322 insert->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001323 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001324
1325 return insert->getResultId();
1326}
1327
1328// An opcode that has no operands, no result id, and no type
1329void Builder::createNoResultOp(Op opCode)
1330{
1331 Instruction* op = new Instruction(opCode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001332 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001333}
1334
John Kessenich149afc32018-08-14 13:31:43 -06001335// An opcode that has one id operand, no result id, and no type
John Kessenich140f3df2015-06-26 16:58:36 -06001336void Builder::createNoResultOp(Op opCode, Id operand)
1337{
1338 Instruction* op = new Instruction(opCode);
1339 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001340 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001341}
1342
John Kessenich149afc32018-08-14 13:31:43 -06001343// An opcode that has multiple operands, no result id, and no type
1344void Builder::createNoResultOp(Op opCode, const std::vector<IdImmediate>& operands)
Rex Xufc618912015-09-09 16:42:49 +08001345{
1346 Instruction* op = new Instruction(opCode);
John Kessenich149afc32018-08-14 13:31:43 -06001347 for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
1348 if (it->isId)
1349 op->addIdOperand(it->word);
1350 else
1351 op->addImmediateOperand(it->word);
1352 }
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001353 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
Rex Xufc618912015-09-09 16:42:49 +08001354}
1355
John Kessenich5e4b1242015-08-06 22:53:06 -06001356void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
John Kessenich140f3df2015-06-26 16:58:36 -06001357{
1358 Instruction* op = new Instruction(OpControlBarrier);
John Kessenich228e9642018-08-13 21:37:59 -06001359 op->addIdOperand(makeUintConstant(execution));
1360 op->addIdOperand(makeUintConstant(memory));
1361 op->addIdOperand(makeUintConstant(semantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001362 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001363}
1364
1365void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
1366{
1367 Instruction* op = new Instruction(OpMemoryBarrier);
John Kessenich228e9642018-08-13 21:37:59 -06001368 op->addIdOperand(makeUintConstant(executionScope));
1369 op->addIdOperand(makeUintConstant(memorySemantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001370 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001371}
1372
1373// An opcode that has one operands, a result id, and a type
1374Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
1375{
qining13545202016-03-21 09:51:37 -04001376 // Generate code for spec constants if in spec constant operation
1377 // generation mode.
1378 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001379 return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
qining13545202016-03-21 09:51:37 -04001380 }
John Kessenich140f3df2015-06-26 16:58:36 -06001381 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1382 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001383 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001384
1385 return op->getResultId();
1386}
1387
1388Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
1389{
qining13545202016-03-21 09:51:37 -04001390 // Generate code for spec constants if in spec constant operation
1391 // generation mode.
1392 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001393 std::vector<Id> operands(2);
1394 operands[0] = left; operands[1] = right;
1395 return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
qining13545202016-03-21 09:51:37 -04001396 }
John Kessenich140f3df2015-06-26 16:58:36 -06001397 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1398 op->addIdOperand(left);
1399 op->addIdOperand(right);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001400 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001401
1402 return op->getResultId();
1403}
1404
1405Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
1406{
qininge24aa5e2016-04-07 15:40:27 -04001407 // Generate code for spec constants if in spec constant operation
1408 // generation mode.
1409 if (generatingOpCodeForSpecConst) {
1410 std::vector<Id> operands(3);
qining189b2032016-04-12 23:16:20 -04001411 operands[0] = op1;
1412 operands[1] = op2;
1413 operands[2] = op3;
qininge24aa5e2016-04-07 15:40:27 -04001414 return createSpecConstantOp(
1415 opCode, typeId, operands, std::vector<Id>());
1416 }
John Kessenich140f3df2015-06-26 16:58:36 -06001417 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1418 op->addIdOperand(op1);
1419 op->addIdOperand(op2);
1420 op->addIdOperand(op3);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001421 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001422
1423 return op->getResultId();
1424}
1425
John Kessenich5e4b1242015-08-06 22:53:06 -06001426Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
John Kessenich140f3df2015-06-26 16:58:36 -06001427{
1428 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
rdb32084e82016-02-23 22:17:38 +01001429 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1430 op->addIdOperand(*it);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001431 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001432
1433 return op->getResultId();
1434}
1435
John Kessenich149afc32018-08-14 13:31:43 -06001436Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& operands)
1437{
1438 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1439 for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
1440 if (it->isId)
1441 op->addIdOperand(it->word);
1442 else
1443 op->addImmediateOperand(it->word);
1444 }
1445 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1446
1447 return op->getResultId();
1448}
1449
qining5c61d8e2016-03-31 13:57:28 -04001450Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals)
1451{
qining13545202016-03-21 09:51:37 -04001452 Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
1453 op->addImmediateOperand((unsigned) opCode);
1454 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1455 op->addIdOperand(*it);
1456 for (auto it = literals.cbegin(); it != literals.cend(); ++it)
1457 op->addImmediateOperand(*it);
1458 module.mapInstruction(op);
1459 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
1460
1461 return op->getResultId();
1462}
1463
Vlad Ivanov689490f2017-01-26 20:46:02 +03001464Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
John Kessenich140f3df2015-06-26 16:58:36 -06001465{
1466 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
1467 op->addIdOperand(function->getId());
1468 for (int a = 0; a < (int)args.size(); ++a)
1469 op->addIdOperand(args[a]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001470 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001471
1472 return op->getResultId();
1473}
1474
1475// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001476Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
John Kessenich140f3df2015-06-26 16:58:36 -06001477{
1478 if (channels.size() == 1)
John Kessenich32cfd492016-02-02 12:37:46 -07001479 return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001480
qining13545202016-03-21 09:51:37 -04001481 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001482 std::vector<Id> operands(2);
1483 operands[0] = operands[1] = source;
1484 return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
qining13545202016-03-21 09:51:37 -04001485 }
John Kessenich140f3df2015-06-26 16:58:36 -06001486 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1487 assert(isVector(source));
1488 swizzle->addIdOperand(source);
1489 swizzle->addIdOperand(source);
1490 for (int i = 0; i < (int)channels.size(); ++i)
1491 swizzle->addImmediateOperand(channels[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001492 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001493
John Kessenich32cfd492016-02-02 12:37:46 -07001494 return setPrecision(swizzle->getResultId(), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001495}
1496
1497// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001498Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
John Kessenich140f3df2015-06-26 16:58:36 -06001499{
John Kessenich140f3df2015-06-26 16:58:36 -06001500 if (channels.size() == 1 && getNumComponents(source) == 1)
1501 return createCompositeInsert(source, target, typeId, channels.front());
1502
1503 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
John Kessenich5c3eed52018-02-05 14:44:14 -07001504
John Kessenich140f3df2015-06-26 16:58:36 -06001505 assert(isVector(target));
1506 swizzle->addIdOperand(target);
John Kessenich5c3eed52018-02-05 14:44:14 -07001507
1508 assert(getNumComponents(source) == (int)channels.size());
1509 assert(isVector(source));
1510 swizzle->addIdOperand(source);
John Kessenich140f3df2015-06-26 16:58:36 -06001511
1512 // Set up an identity shuffle from the base value to the result value
1513 unsigned int components[4];
1514 int numTargetComponents = getNumComponents(target);
1515 for (int i = 0; i < numTargetComponents; ++i)
1516 components[i] = i;
1517
1518 // Punch in the l-value swizzle
John Kessenich5c3eed52018-02-05 14:44:14 -07001519 for (int i = 0; i < (int)channels.size(); ++i)
1520 components[channels[i]] = numTargetComponents + i;
John Kessenich140f3df2015-06-26 16:58:36 -06001521
1522 // finish the instruction with these components selectors
1523 for (int i = 0; i < numTargetComponents; ++i)
1524 swizzle->addImmediateOperand(components[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001525 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001526
1527 return swizzle->getResultId();
1528}
1529
1530// Comments in header
1531void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
1532{
1533 int direction = getNumComponents(right) - getNumComponents(left);
1534
1535 if (direction > 0)
John Kessenich76f71392015-12-09 19:08:42 -07001536 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
John Kessenich140f3df2015-06-26 16:58:36 -06001537 else if (direction < 0)
John Kessenich76f71392015-12-09 19:08:42 -07001538 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
John Kessenich140f3df2015-06-26 16:58:36 -06001539
1540 return;
1541}
1542
1543// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001544Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
John Kessenich140f3df2015-06-26 16:58:36 -06001545{
1546 assert(getNumComponents(scalar) == 1);
John Kessenich76f71392015-12-09 19:08:42 -07001547 assert(getTypeId(scalar) == getScalarTypeId(vectorType));
John Kessenich140f3df2015-06-26 16:58:36 -06001548
1549 int numComponents = getNumTypeComponents(vectorType);
1550 if (numComponents == 1)
1551 return scalar;
1552
qining13545202016-03-21 09:51:37 -04001553 Instruction* smear = nullptr;
1554 if (generatingOpCodeForSpecConst) {
1555 auto members = std::vector<spv::Id>(numComponents, scalar);
qining1f2820a2016-04-14 18:34:27 -04001556 // Sometime even in spec-constant-op mode, the temporary vector created by
1557 // promoting a scalar might not be a spec constant. This should depend on
1558 // the scalar.
1559 // e.g.:
1560 // const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
1561 // In such cases, the temporary vector created from a_front_end_const_scalar
1562 // is not a spec constant vector, even though the binary operation node is marked
1563 // as 'specConstant' and we are in spec-constant-op mode.
qining27e04a02016-04-14 16:40:20 -04001564 auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
qining13545202016-03-21 09:51:37 -04001565 smear = module.getInstruction(result_id);
1566 } else {
1567 smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
1568 for (int c = 0; c < numComponents; ++c)
1569 smear->addIdOperand(scalar);
1570 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
1571 }
John Kessenich140f3df2015-06-26 16:58:36 -06001572
John Kessenich32cfd492016-02-02 12:37:46 -07001573 return setPrecision(smear->getResultId(), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001574}
1575
1576// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001577Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
John Kessenich140f3df2015-06-26 16:58:36 -06001578{
1579 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
1580 inst->addIdOperand(builtins);
1581 inst->addImmediateOperand(entryPoint);
1582 for (int arg = 0; arg < (int)args.size(); ++arg)
1583 inst->addIdOperand(args[arg]);
1584
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001585 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich32cfd492016-02-02 12:37:46 -07001586
John Kessenich140f3df2015-06-26 16:58:36 -06001587 return inst->getResultId();
1588}
1589
1590// Accept all parameters needed to create a texture instruction.
1591// Create the correct instruction based on the inputs, and make the call.
John Kessenichba018e62018-06-05 08:53:36 -06001592Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
1593 bool noImplicitLod, const TextureParameters& parameters)
John Kessenich140f3df2015-06-26 16:58:36 -06001594{
John Kessenich5e4b1242015-08-06 22:53:06 -06001595 static const int maxTextureArgs = 10;
John Kessenich140f3df2015-06-26 16:58:36 -06001596 Id texArgs[maxTextureArgs] = {};
1597
1598 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001599 // Set up the fixed arguments
John Kessenich140f3df2015-06-26 16:58:36 -06001600 //
John Kessenich140f3df2015-06-26 16:58:36 -06001601 int numArgs = 0;
John Kessenich019f08f2016-02-15 15:40:42 -07001602 bool explicitLod = false;
John Kessenich140f3df2015-06-26 16:58:36 -06001603 texArgs[numArgs++] = parameters.sampler;
1604 texArgs[numArgs++] = parameters.coords;
John Kessenich76d4dfc2016-06-16 12:43:23 -06001605 if (parameters.Dref != NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001606 texArgs[numArgs++] = parameters.Dref;
John Kessenich76d4dfc2016-06-16 12:43:23 -06001607 if (parameters.component != NoResult)
1608 texArgs[numArgs++] = parameters.component;
John Kessenich140f3df2015-06-26 16:58:36 -06001609
1610 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001611 // Set up the optional arguments
1612 //
1613 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
1614 ++numArgs; // speculatively make room for the mask operand
1615 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
1616 if (parameters.bias) {
1617 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
1618 texArgs[numArgs++] = parameters.bias;
1619 }
1620 if (parameters.lod) {
1621 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1622 texArgs[numArgs++] = parameters.lod;
John Kessenich019f08f2016-02-15 15:40:42 -07001623 explicitLod = true;
1624 } else if (parameters.gradX) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001625 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
1626 texArgs[numArgs++] = parameters.gradX;
1627 texArgs[numArgs++] = parameters.gradY;
John Kessenich019f08f2016-02-15 15:40:42 -07001628 explicitLod = true;
1629 } else if (noImplicitLod && ! fetch && ! gather) {
1630 // have to explicitly use lod of 0 if not allowed to have them be implicit, and
1631 // we would otherwise be about to issue an implicit instruction
1632 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1633 texArgs[numArgs++] = makeFloatConstant(0.0);
1634 explicitLod = true;
John Kessenich5e4b1242015-08-06 22:53:06 -06001635 }
1636 if (parameters.offset) {
Rex Xu86e60812015-10-11 19:37:48 +08001637 if (isConstant(parameters.offset))
1638 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
Rex Xu58390312016-05-11 16:38:50 +08001639 else {
1640 addCapability(CapabilityImageGatherExtended);
Rex Xu86e60812015-10-11 19:37:48 +08001641 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
Rex Xu58390312016-05-11 16:38:50 +08001642 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001643 texArgs[numArgs++] = parameters.offset;
1644 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001645 if (parameters.offsets) {
John Kessenichba018e62018-06-05 08:53:36 -06001646 addCapability(CapabilityImageGatherExtended);
John Kessenich5e4b1242015-08-06 22:53:06 -06001647 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
1648 texArgs[numArgs++] = parameters.offsets;
1649 }
1650 if (parameters.sample) {
1651 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
1652 texArgs[numArgs++] = parameters.sample;
1653 }
Rex Xu48edadf2015-12-31 16:11:41 +08001654 if (parameters.lodClamp) {
John Kessenich5e801132016-02-15 11:09:46 -07001655 // capability if this bit is used
1656 addCapability(CapabilityMinLod);
1657
Rex Xu48edadf2015-12-31 16:11:41 +08001658 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
1659 texArgs[numArgs++] = parameters.lodClamp;
1660 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001661 if (mask == ImageOperandsMaskNone)
1662 --numArgs; // undo speculative reservation for the mask argument
1663 else
1664 texArgs[optArgNum] = mask;
1665
1666 //
John Kessenich140f3df2015-06-26 16:58:36 -06001667 // Set up the instruction
1668 //
John Kessenich019f08f2016-02-15 15:40:42 -07001669 Op opCode = OpNop; // All paths below need to set this
Jason Ekstrand18b9fbd2015-09-05 14:14:48 -07001670 if (fetch) {
Rex Xu48edadf2015-12-31 16:11:41 +08001671 if (sparse)
1672 opCode = OpImageSparseFetch;
1673 else
1674 opCode = OpImageFetch;
John Kessenich55e7d112015-11-15 21:33:39 -07001675 } else if (gather) {
1676 if (parameters.Dref)
Rex Xu48edadf2015-12-31 16:11:41 +08001677 if (sparse)
1678 opCode = OpImageSparseDrefGather;
1679 else
1680 opCode = OpImageDrefGather;
John Kessenich55e7d112015-11-15 21:33:39 -07001681 else
Rex Xu48edadf2015-12-31 16:11:41 +08001682 if (sparse)
1683 opCode = OpImageSparseGather;
1684 else
1685 opCode = OpImageGather;
John Kessenich019f08f2016-02-15 15:40:42 -07001686 } else if (explicitLod) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001687 if (parameters.Dref) {
1688 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001689 if (sparse)
1690 opCode = OpImageSparseSampleProjDrefExplicitLod;
1691 else
1692 opCode = OpImageSampleProjDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001693 else
Rex Xu48edadf2015-12-31 16:11:41 +08001694 if (sparse)
1695 opCode = OpImageSparseSampleDrefExplicitLod;
1696 else
1697 opCode = OpImageSampleDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001698 } else {
1699 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001700 if (sparse)
1701 opCode = OpImageSparseSampleProjExplicitLod;
1702 else
1703 opCode = OpImageSampleProjExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001704 else
Rex Xu48edadf2015-12-31 16:11:41 +08001705 if (sparse)
1706 opCode = OpImageSparseSampleExplicitLod;
1707 else
1708 opCode = OpImageSampleExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001709 }
1710 } else {
1711 if (parameters.Dref) {
1712 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001713 if (sparse)
1714 opCode = OpImageSparseSampleProjDrefImplicitLod;
1715 else
1716 opCode = OpImageSampleProjDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001717 else
Rex Xu48edadf2015-12-31 16:11:41 +08001718 if (sparse)
1719 opCode = OpImageSparseSampleDrefImplicitLod;
1720 else
1721 opCode = OpImageSampleDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001722 } else {
1723 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001724 if (sparse)
1725 opCode = OpImageSparseSampleProjImplicitLod;
1726 else
1727 opCode = OpImageSampleProjImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001728 else
Rex Xu48edadf2015-12-31 16:11:41 +08001729 if (sparse)
1730 opCode = OpImageSparseSampleImplicitLod;
1731 else
1732 opCode = OpImageSampleImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001733 }
1734 }
John Kessenich140f3df2015-06-26 16:58:36 -06001735
John Kessenich7355eeb2015-09-14 22:08:12 -06001736 // See if the result type is expecting a smeared result.
1737 // This happens when a legacy shadow*() call is made, which
1738 // gets a vec4 back instead of a float.
1739 Id smearedType = resultType;
1740 if (! isScalarType(resultType)) {
1741 switch (opCode) {
1742 case OpImageSampleDrefImplicitLod:
1743 case OpImageSampleDrefExplicitLod:
1744 case OpImageSampleProjDrefImplicitLod:
1745 case OpImageSampleProjDrefExplicitLod:
1746 resultType = getScalarTypeId(resultType);
1747 break;
1748 default:
1749 break;
1750 }
1751 }
1752
Rex Xu48edadf2015-12-31 16:11:41 +08001753 Id typeId0 = 0;
1754 Id typeId1 = 0;
1755
1756 if (sparse) {
1757 typeId0 = resultType;
1758 typeId1 = getDerefTypeId(parameters.texelOut);
1759 resultType = makeStructResultType(typeId0, typeId1);
1760 }
1761
John Kessenich55e7d112015-11-15 21:33:39 -07001762 // Build the SPIR-V instruction
John Kessenich140f3df2015-06-26 16:58:36 -06001763 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
John Kessenich5e4b1242015-08-06 22:53:06 -06001764 for (int op = 0; op < optArgNum; ++op)
1765 textureInst->addIdOperand(texArgs[op]);
1766 if (optArgNum < numArgs)
1767 textureInst->addImmediateOperand(texArgs[optArgNum]);
1768 for (int op = optArgNum + 1; op < numArgs; ++op)
John Kessenich140f3df2015-06-26 16:58:36 -06001769 textureInst->addIdOperand(texArgs[op]);
1770 setPrecision(textureInst->getResultId(), precision);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001771 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
John Kessenich140f3df2015-06-26 16:58:36 -06001772
John Kessenich7355eeb2015-09-14 22:08:12 -06001773 Id resultId = textureInst->getResultId();
1774
Rex Xu48edadf2015-12-31 16:11:41 +08001775 if (sparse) {
John Kessenich5e801132016-02-15 11:09:46 -07001776 // set capability
1777 addCapability(CapabilitySparseResidency);
1778
Rex Xu48edadf2015-12-31 16:11:41 +08001779 // Decode the return type that was a special structure
1780 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
1781 resultId = createCompositeExtract(resultId, typeId0, 0);
John Kessenich32cfd492016-02-02 12:37:46 -07001782 setPrecision(resultId, precision);
Rex Xu48edadf2015-12-31 16:11:41 +08001783 } else {
1784 // When a smear is needed, do it, as per what was computed
1785 // above when resultType was changed to a scalar type.
1786 if (resultType != smearedType)
1787 resultId = smearScalar(precision, resultId, smearedType);
1788 }
John Kessenich7355eeb2015-09-14 22:08:12 -06001789
1790 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001791}
1792
1793// Comments in header
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001794Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001795{
1796 // Figure out the result type
John Kessenich5e4b1242015-08-06 22:53:06 -06001797 Id resultType = 0;
John Kessenich140f3df2015-06-26 16:58:36 -06001798 switch (opCode) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001799 case OpImageQuerySize:
1800 case OpImageQuerySizeLod:
John Kessenich140f3df2015-06-26 16:58:36 -06001801 {
Mark Adams364c21c2016-01-06 13:41:02 -05001802 int numComponents = 0;
John Kessenich5e4b1242015-08-06 22:53:06 -06001803 switch (getTypeDimensionality(getImageType(parameters.sampler))) {
John Kessenich140f3df2015-06-26 16:58:36 -06001804 case Dim1D:
1805 case DimBuffer:
1806 numComponents = 1;
1807 break;
1808 case Dim2D:
1809 case DimCube:
1810 case DimRect:
John Kessenich50e57562015-12-21 21:21:11 -07001811 case DimSubpassData:
John Kessenich140f3df2015-06-26 16:58:36 -06001812 numComponents = 2;
1813 break;
1814 case Dim3D:
1815 numComponents = 3;
1816 break;
John Kessenich55e7d112015-11-15 21:33:39 -07001817
John Kessenich140f3df2015-06-26 16:58:36 -06001818 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001819 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -06001820 break;
1821 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001822 if (isArrayedImageType(getImageType(parameters.sampler)))
John Kessenich140f3df2015-06-26 16:58:36 -06001823 ++numComponents;
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001824
1825 Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
John Kessenich140f3df2015-06-26 16:58:36 -06001826 if (numComponents == 1)
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001827 resultType = intType;
John Kessenich140f3df2015-06-26 16:58:36 -06001828 else
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001829 resultType = makeVectorType(intType, numComponents);
John Kessenich140f3df2015-06-26 16:58:36 -06001830
1831 break;
1832 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001833 case OpImageQueryLod:
Rex Xu1e5d7b02016-11-29 17:36:31 +08001834#ifdef AMD_EXTENSIONS
1835 resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2);
1836#else
John Kessenich140f3df2015-06-26 16:58:36 -06001837 resultType = makeVectorType(makeFloatType(32), 2);
Rex Xu1e5d7b02016-11-29 17:36:31 +08001838#endif
John Kessenich140f3df2015-06-26 16:58:36 -06001839 break;
John Kessenich5e4b1242015-08-06 22:53:06 -06001840 case OpImageQueryLevels:
1841 case OpImageQuerySamples:
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001842 resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
John Kessenich140f3df2015-06-26 16:58:36 -06001843 break;
1844 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001845 assert(0);
1846 break;
John Kessenich140f3df2015-06-26 16:58:36 -06001847 }
1848
1849 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
1850 query->addIdOperand(parameters.sampler);
1851 if (parameters.coords)
1852 query->addIdOperand(parameters.coords);
1853 if (parameters.lod)
1854 query->addIdOperand(parameters.lod);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001855 buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
John Kessenich140f3df2015-06-26 16:58:36 -06001856
1857 return query->getResultId();
1858}
1859
John Kessenich22118352015-12-21 20:54:09 -07001860// External comments in header.
1861// Operates recursively to visit the composite's hierarchy.
1862Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
John Kessenich140f3df2015-06-26 16:58:36 -06001863{
1864 Id boolType = makeBoolType();
1865 Id valueType = getTypeId(value1);
1866
Mark Adamsd5ac5382016-02-01 19:13:06 -08001867 Id resultId = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001868
John Kessenich22118352015-12-21 20:54:09 -07001869 int numConstituents = getNumTypeConstituents(valueType);
John Kessenich140f3df2015-06-26 16:58:36 -06001870
John Kessenich22118352015-12-21 20:54:09 -07001871 // Scalars and Vectors
1872
1873 if (isScalarType(valueType) || isVectorType(valueType)) {
John Kesseniche23c9842016-01-04 23:49:03 -07001874 assert(valueType == getTypeId(value2));
John Kessenich22118352015-12-21 20:54:09 -07001875 // These just need a single comparison, just have
1876 // to figure out what it is.
John Kessenich140f3df2015-06-26 16:58:36 -06001877 Op op;
John Kessenich22118352015-12-21 20:54:09 -07001878 switch (getMostBasicTypeClass(valueType)) {
1879 case OpTypeFloat:
John Kessenich140f3df2015-06-26 16:58:36 -06001880 op = equal ? OpFOrdEqual : OpFOrdNotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001881 break;
1882 case OpTypeInt:
Mark Adamsd5ac5382016-02-01 19:13:06 -08001883 default:
John Kessenich140f3df2015-06-26 16:58:36 -06001884 op = equal ? OpIEqual : OpINotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001885 break;
1886 case OpTypeBool:
1887 op = equal ? OpLogicalEqual : OpLogicalNotEqual;
1888 precision = NoPrecision;
1889 break;
1890 }
John Kessenich140f3df2015-06-26 16:58:36 -06001891
John Kessenich22118352015-12-21 20:54:09 -07001892 if (isScalarType(valueType)) {
1893 // scalar
1894 resultId = createBinOp(op, boolType, value1, value2);
John Kessenich22118352015-12-21 20:54:09 -07001895 } else {
1896 // vector
1897 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
1898 setPrecision(resultId, precision);
1899 // reduce vector compares...
1900 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
1901 }
John Kessenich140f3df2015-06-26 16:58:36 -06001902
John Kessenich32cfd492016-02-02 12:37:46 -07001903 return setPrecision(resultId, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001904 }
1905
John Kessenich22118352015-12-21 20:54:09 -07001906 // Only structs, arrays, and matrices should be left.
1907 // They share in common the reduction operation across their constituents.
1908 assert(isAggregateType(valueType) || isMatrixType(valueType));
John Kessenich140f3df2015-06-26 16:58:36 -06001909
John Kessenich22118352015-12-21 20:54:09 -07001910 // Compare each pair of constituents
1911 for (int constituent = 0; constituent < numConstituents; ++constituent) {
1912 std::vector<unsigned> indexes(1, constituent);
John Kesseniche23c9842016-01-04 23:49:03 -07001913 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
1914 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
1915 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
1916 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06001917
John Kessenich22118352015-12-21 20:54:09 -07001918 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
John Kessenich140f3df2015-06-26 16:58:36 -06001919
John Kessenich22118352015-12-21 20:54:09 -07001920 if (constituent == 0)
1921 resultId = subResultId;
1922 else
John Kessenich32cfd492016-02-02 12:37:46 -07001923 resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision);
John Kessenich22118352015-12-21 20:54:09 -07001924 }
John Kessenich140f3df2015-06-26 16:58:36 -06001925
John Kessenich22118352015-12-21 20:54:09 -07001926 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001927}
1928
John Kessenich140f3df2015-06-26 16:58:36 -06001929// OpCompositeConstruct
Vlad Ivanov689490f2017-01-26 20:46:02 +03001930Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
John Kessenich140f3df2015-06-26 16:58:36 -06001931{
John Kessenich22118352015-12-21 20:54:09 -07001932 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size()));
John Kessenich140f3df2015-06-26 16:58:36 -06001933
qining27e04a02016-04-14 16:40:20 -04001934 if (generatingOpCodeForSpecConst) {
qining1f2820a2016-04-14 18:34:27 -04001935 // Sometime, even in spec-constant-op mode, the constant composite to be
1936 // constructed may not be a specialization constant.
1937 // e.g.:
1938 // const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
1939 // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
1940 // The second column vector should NOT be spec constant, as it does not contain any spec constants.
1941 // To handle such cases, we check the constituents of the constant vector to determine whether this
1942 // vector should be created as a spec constant.
1943 return makeCompositeConstant(typeId, constituents,
1944 std::any_of(constituents.begin(), constituents.end(),
1945 [&](spv::Id id) { return isSpecConstant(id); }));
qining27e04a02016-04-14 16:40:20 -04001946 }
1947
John Kessenich140f3df2015-06-26 16:58:36 -06001948 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
1949 for (int c = 0; c < (int)constituents.size(); ++c)
1950 op->addIdOperand(constituents[c]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001951 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001952
1953 return op->getResultId();
1954}
1955
1956// Vector or scalar constructor
1957Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1958{
John Kessenich32cfd492016-02-02 12:37:46 -07001959 Id result = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001960 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
1961 unsigned int targetComponent = 0;
1962
1963 // Special case: when calling a vector constructor with a single scalar
1964 // argument, smear the scalar
1965 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
1966 return smearScalar(precision, sources[0], resultTypeId);
1967
John Kessenich0302bdf2017-02-17 19:06:21 -07001968 // accumulate the arguments for OpCompositeConstruct
1969 std::vector<Id> constituents;
John Kessenich140f3df2015-06-26 16:58:36 -06001970 Id scalarTypeId = getScalarTypeId(resultTypeId);
John Kessenich0302bdf2017-02-17 19:06:21 -07001971
1972 // lambda to store the result of visiting an argument component
1973 const auto latchResult = [&](Id comp) {
1974 if (numTargetComponents > 1)
1975 constituents.push_back(comp);
1976 else
1977 result = comp;
1978 ++targetComponent;
1979 };
1980
1981 // lambda to visit a vector argument's components
1982 const auto accumulateVectorConstituents = [&](Id sourceArg) {
1983 unsigned int sourceSize = getNumComponents(sourceArg);
John Kessenich140f3df2015-06-26 16:58:36 -06001984 unsigned int sourcesToUse = sourceSize;
1985 if (sourcesToUse + targetComponent > numTargetComponents)
1986 sourcesToUse = numTargetComponents - targetComponent;
1987
1988 for (unsigned int s = 0; s < sourcesToUse; ++s) {
John Kessenich0302bdf2017-02-17 19:06:21 -07001989 std::vector<unsigned> swiz;
1990 swiz.push_back(s);
1991 latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
John Kessenich140f3df2015-06-26 16:58:36 -06001992 }
John Kessenich0302bdf2017-02-17 19:06:21 -07001993 };
1994
1995 // lambda to visit a matrix argument's components
1996 const auto accumulateMatrixConstituents = [&](Id sourceArg) {
1997 unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
1998 unsigned int sourcesToUse = sourceSize;
1999 if (sourcesToUse + targetComponent > numTargetComponents)
2000 sourcesToUse = numTargetComponents - targetComponent;
2001
2002 int col = 0;
2003 int row = 0;
2004 for (unsigned int s = 0; s < sourcesToUse; ++s) {
2005 if (row >= getNumRows(sourceArg)) {
2006 row = 0;
2007 col++;
2008 }
2009 std::vector<Id> indexes;
2010 indexes.push_back(col);
2011 indexes.push_back(row);
2012 latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
2013 row++;
2014 }
2015 };
2016
2017 // Go through the source arguments, each one could have either
2018 // a single or multiple components to contribute.
2019 for (unsigned int i = 0; i < sources.size(); ++i) {
2020 if (isScalar(sources[i]))
2021 latchResult(sources[i]);
2022 else if (isVector(sources[i]))
2023 accumulateVectorConstituents(sources[i]);
2024 else if (isMatrix(sources[i]))
2025 accumulateMatrixConstituents(sources[i]);
2026 else
2027 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -06002028
2029 if (targetComponent >= numTargetComponents)
2030 break;
2031 }
2032
John Kessenich0302bdf2017-02-17 19:06:21 -07002033 // If the result is a vector, make it from the gathered constituents.
John Kessenich140f3df2015-06-26 16:58:36 -06002034 if (constituents.size() > 0)
2035 result = createCompositeConstruct(resultTypeId, constituents);
2036
John Kessenich32cfd492016-02-02 12:37:46 -07002037 return setPrecision(result, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002038}
2039
2040// Comments in header
2041Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
2042{
2043 Id componentTypeId = getScalarTypeId(resultTypeId);
2044 int numCols = getTypeNumColumns(resultTypeId);
2045 int numRows = getTypeNumRows(resultTypeId);
2046
iostrowsaf7f1c82016-06-01 16:40:00 +02002047 Instruction* instr = module.getInstruction(componentTypeId);
John Kessenich228e9642018-08-13 21:37:59 -06002048 unsigned bitCount = instr->getImmediateOperand(0);
iostrowsaf7f1c82016-06-01 16:40:00 +02002049
John Kessenich5a7321e2018-07-20 15:28:38 -06002050 // Optimize matrix constructed from a bigger matrix
Arseny Kapoulkine112e2852018-07-05 13:19:39 -07002051 if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) {
2052 // To truncate the matrix to a smaller number of rows/columns, we need to:
2053 // 1. For each column, extract the column and truncate it to the required size using shuffle
2054 // 2. Assemble the resulting matrix from all columns
John Kessenich140f3df2015-06-26 16:58:36 -06002055 Id matrix = sources[0];
Arseny Kapoulkine112e2852018-07-05 13:19:39 -07002056 Id columnTypeId = getContainedTypeId(resultTypeId);
2057 Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix));
2058
2059 std::vector<unsigned> channels;
John Kessenich5a7321e2018-07-20 15:28:38 -06002060 for (int row = 0; row < numRows; ++row)
Arseny Kapoulkine112e2852018-07-05 13:19:39 -07002061 channels.push_back(row);
Arseny Kapoulkine112e2852018-07-05 13:19:39 -07002062
2063 std::vector<Id> matrixColumns;
2064 for (int col = 0; col < numCols; ++col) {
John Kessenich140f3df2015-06-26 16:58:36 -06002065 std::vector<unsigned> indexes;
2066 indexes.push_back(col);
Arseny Kapoulkine112e2852018-07-05 13:19:39 -07002067 Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes);
2068 setPrecision(colv, precision);
2069
2070 if (numRows != getNumRows(matrix)) {
2071 matrixColumns.push_back(createRvalueSwizzle(precision, columnTypeId, colv, channels));
2072 } else {
2073 matrixColumns.push_back(colv);
John Kessenich140f3df2015-06-26 16:58:36 -06002074 }
2075 }
Arseny Kapoulkine112e2852018-07-05 13:19:39 -07002076
2077 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002078 }
John Kessenich5a7321e2018-07-20 15:28:38 -06002079
2080 // Otherwise, will use a two step process
John Kessenich140f3df2015-06-26 16:58:36 -06002081 // 1. make a compile-time 2D array of values
2082 // 2. construct a matrix from that array
2083
2084 // Step 1.
2085
2086 // initialize the array to the identity matrix
2087 Id ids[maxMatrixSize][maxMatrixSize];
2088 Id one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
2089 Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
2090 for (int col = 0; col < 4; ++col) {
2091 for (int row = 0; row < 4; ++row) {
2092 if (col == row)
2093 ids[col][row] = one;
2094 else
2095 ids[col][row] = zero;
2096 }
2097 }
2098
2099 // modify components as dictated by the arguments
2100 if (sources.size() == 1 && isScalar(sources[0])) {
2101 // a single scalar; resets the diagonals
2102 for (int col = 0; col < 4; ++col)
2103 ids[col][col] = sources[0];
2104 } else if (isMatrix(sources[0])) {
2105 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
2106 Id matrix = sources[0];
2107 int minCols = std::min(numCols, getNumColumns(matrix));
2108 int minRows = std::min(numRows, getNumRows(matrix));
2109 for (int col = 0; col < minCols; ++col) {
2110 std::vector<unsigned> indexes;
2111 indexes.push_back(col);
2112 for (int row = 0; row < minRows; ++row) {
2113 indexes.push_back(row);
2114 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
2115 indexes.pop_back();
2116 setPrecision(ids[col][row], precision);
2117 }
2118 }
2119 } else {
2120 // fill in the matrix in column-major order with whatever argument components are available
2121 int row = 0;
2122 int col = 0;
2123
2124 for (int arg = 0; arg < (int)sources.size(); ++arg) {
2125 Id argComp = sources[arg];
2126 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
2127 if (getNumComponents(sources[arg]) > 1) {
2128 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
2129 setPrecision(argComp, precision);
2130 }
2131 ids[col][row++] = argComp;
2132 if (row == numRows) {
2133 row = 0;
2134 col++;
2135 }
2136 }
2137 }
2138 }
2139
John Kessenich140f3df2015-06-26 16:58:36 -06002140 // Step 2: Construct a matrix from that array.
2141 // First make the column vectors, then make the matrix.
2142
2143 // make the column vectors
2144 Id columnTypeId = getContainedTypeId(resultTypeId);
2145 std::vector<Id> matrixColumns;
2146 for (int col = 0; col < numCols; ++col) {
2147 std::vector<Id> vectorComponents;
2148 for (int row = 0; row < numRows; ++row)
2149 vectorComponents.push_back(ids[col][row]);
John Kessenich32cfd492016-02-02 12:37:46 -07002150 Id column = createCompositeConstruct(columnTypeId, vectorComponents);
2151 setPrecision(column, precision);
2152 matrixColumns.push_back(column);
John Kessenich140f3df2015-06-26 16:58:36 -06002153 }
2154
2155 // make the matrix
John Kessenich32cfd492016-02-02 12:37:46 -07002156 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002157}
2158
2159// Comments in header
Rex Xu57e65922017-07-04 23:23:40 +08002160Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
John Kessenich140f3df2015-06-26 16:58:36 -06002161 builder(gb),
2162 condition(cond),
Rex Xu57e65922017-07-04 23:23:40 +08002163 control(ctrl),
John Kessenich140f3df2015-06-26 16:58:36 -06002164 elseBlock(0)
2165{
2166 function = &builder.getBuildPoint()->getParent();
2167
2168 // make the blocks, but only put the then-block into the function,
2169 // the else-block and merge-block will be added later, in order, after
2170 // earlier code is emitted
2171 thenBlock = new Block(builder.getUniqueId(), *function);
2172 mergeBlock = new Block(builder.getUniqueId(), *function);
2173
2174 // Save the current block, so that we can add in the flow control split when
2175 // makeEndIf is called.
2176 headerBlock = builder.getBuildPoint();
2177
2178 function->addBlock(thenBlock);
2179 builder.setBuildPoint(thenBlock);
2180}
2181
2182// Comments in header
2183void Builder::If::makeBeginElse()
2184{
2185 // Close out the "then" by having it jump to the mergeBlock
2186 builder.createBranch(mergeBlock);
2187
2188 // Make the first else block and add it to the function
2189 elseBlock = new Block(builder.getUniqueId(), *function);
2190 function->addBlock(elseBlock);
2191
2192 // Start building the else block
2193 builder.setBuildPoint(elseBlock);
2194}
2195
2196// Comments in header
2197void Builder::If::makeEndIf()
2198{
2199 // jump to the merge block
2200 builder.createBranch(mergeBlock);
2201
2202 // Go back to the headerBlock and make the flow control split
2203 builder.setBuildPoint(headerBlock);
Rex Xu57e65922017-07-04 23:23:40 +08002204 builder.createSelectionMerge(mergeBlock, control);
John Kessenich140f3df2015-06-26 16:58:36 -06002205 if (elseBlock)
2206 builder.createConditionalBranch(condition, thenBlock, elseBlock);
2207 else
2208 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
2209
2210 // add the merge block to the function
2211 function->addBlock(mergeBlock);
2212 builder.setBuildPoint(mergeBlock);
2213}
2214
2215// Comments in header
Rex Xu57e65922017-07-04 23:23:40 +08002216void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
Vlad Ivanov689490f2017-01-26 20:46:02 +03002217 const std::vector<int>& valueIndexToSegment, int defaultSegment,
John Kessenich140f3df2015-06-26 16:58:36 -06002218 std::vector<Block*>& segmentBlocks)
2219{
2220 Function& function = buildPoint->getParent();
2221
2222 // make all the blocks
2223 for (int s = 0; s < numSegments; ++s)
2224 segmentBlocks.push_back(new Block(getUniqueId(), function));
2225
2226 Block* mergeBlock = new Block(getUniqueId(), function);
2227
2228 // make and insert the switch's selection-merge instruction
Rex Xu57e65922017-07-04 23:23:40 +08002229 createSelectionMerge(mergeBlock, control);
John Kessenich140f3df2015-06-26 16:58:36 -06002230
2231 // make the switch instruction
2232 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
2233 switchInst->addIdOperand(selector);
Dejan Mircevski454796e2016-01-18 16:18:01 -05002234 auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
2235 switchInst->addIdOperand(defaultOrMerge->getId());
2236 defaultOrMerge->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06002237 for (int i = 0; i < (int)caseValues.size(); ++i) {
2238 switchInst->addImmediateOperand(caseValues[i]);
2239 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
Dejan Mircevski454796e2016-01-18 16:18:01 -05002240 segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06002241 }
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002242 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
John Kessenich140f3df2015-06-26 16:58:36 -06002243
2244 // push the merge block
2245 switchMerges.push(mergeBlock);
2246}
2247
2248// Comments in header
2249void Builder::addSwitchBreak()
2250{
2251 // branch to the top of the merge block stack
2252 createBranch(switchMerges.top());
2253 createAndSetNoPredecessorBlock("post-switch-break");
2254}
2255
2256// Comments in header
2257void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
2258{
2259 int lastSegment = nextSegment - 1;
2260 if (lastSegment >= 0) {
2261 // Close out previous segment by jumping, if necessary, to next segment
2262 if (! buildPoint->isTerminated())
2263 createBranch(segmentBlock[nextSegment]);
2264 }
2265 Block* block = segmentBlock[nextSegment];
2266 block->getParent().addBlock(block);
2267 setBuildPoint(block);
2268}
2269
2270// Comments in header
2271void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
2272{
2273 // Close out previous segment by jumping, if necessary, to next segment
2274 if (! buildPoint->isTerminated())
2275 addSwitchBreak();
2276
2277 switchMerges.top()->getParent().addBlock(switchMerges.top());
2278 setBuildPoint(switchMerges.top());
2279
2280 switchMerges.pop();
2281}
2282
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05002283Block& Builder::makeNewBlock()
2284{
2285 Function& function = buildPoint->getParent();
2286 auto block = new Block(getUniqueId(), function);
2287 function.addBlock(block);
2288 return *block;
2289}
2290
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002291Builder::LoopBlocks& Builder::makeNewLoop()
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05002292{
John Kessenich7f349c72016-07-08 22:09:10 -06002293 // This verbosity is needed to simultaneously get the same behavior
2294 // everywhere (id's in the same order), have a syntax that works
2295 // across lots of versions of C++, have no warnings from pedantic
2296 // compilation modes, and leave the rest of the code alone.
2297 Block& head = makeNewBlock();
2298 Block& body = makeNewBlock();
2299 Block& merge = makeNewBlock();
2300 Block& continue_target = makeNewBlock();
2301 LoopBlocks blocks(head, body, merge, continue_target);
Dejan Mircevski97605c82016-01-20 10:19:25 -05002302 loops.push(blocks);
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002303 return loops.top();
John Kessenich140f3df2015-06-26 16:58:36 -06002304}
2305
2306void Builder::createLoopContinue()
2307{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002308 createBranch(&loops.top().continue_target);
John Kessenich140f3df2015-06-26 16:58:36 -06002309 // Set up a block for dead code.
2310 createAndSetNoPredecessorBlock("post-loop-continue");
2311}
2312
John Kessenich140f3df2015-06-26 16:58:36 -06002313void Builder::createLoopExit()
2314{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002315 createBranch(&loops.top().merge);
John Kessenich140f3df2015-06-26 16:58:36 -06002316 // Set up a block for dead code.
2317 createAndSetNoPredecessorBlock("post-loop-break");
2318}
2319
John Kessenich140f3df2015-06-26 16:58:36 -06002320void Builder::closeLoop()
2321{
John Kessenich140f3df2015-06-26 16:58:36 -06002322 loops.pop();
2323}
2324
2325void Builder::clearAccessChain()
2326{
John Kessenichfa668da2015-09-13 14:46:30 -06002327 accessChain.base = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06002328 accessChain.indexChain.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002329 accessChain.instr = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06002330 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002331 accessChain.component = NoResult;
2332 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002333 accessChain.isRValue = false;
2334}
2335
2336// Comments in header
John Kessenichfa668da2015-09-13 14:46:30 -06002337void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
John Kessenich140f3df2015-06-26 16:58:36 -06002338{
John Kessenichfa668da2015-09-13 14:46:30 -06002339 // swizzles can be stacked in GLSL, but simplified to a single
2340 // one here; the base type doesn't change
2341 if (accessChain.preSwizzleBaseType == NoType)
2342 accessChain.preSwizzleBaseType = preSwizzleBaseType;
2343
John Kessenich140f3df2015-06-26 16:58:36 -06002344 // if needed, propagate the swizzle for the current access chain
John Kessenich5c3eed52018-02-05 14:44:14 -07002345 if (accessChain.swizzle.size() > 0) {
John Kessenich140f3df2015-06-26 16:58:36 -06002346 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
2347 accessChain.swizzle.resize(0);
2348 for (unsigned int i = 0; i < swizzle.size(); ++i) {
John Kessenich1e275c82016-12-14 17:02:32 -07002349 assert(swizzle[i] < oldSwizzle.size());
John Kessenich140f3df2015-06-26 16:58:36 -06002350 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
2351 }
2352 } else
2353 accessChain.swizzle = swizzle;
2354
2355 // determine if we need to track this swizzle anymore
2356 simplifyAccessChainSwizzle();
2357}
2358
2359// Comments in header
2360void Builder::accessChainStore(Id rvalue)
2361{
2362 assert(accessChain.isRValue == false);
2363
John Kessenich55e7d112015-11-15 21:33:39 -07002364 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002365 Id base = collapseAccessChain();
John Kessenich5c3eed52018-02-05 14:44:14 -07002366 Id source = rvalue;
2367
2368 // dynamic component should be gone
2369 assert(accessChain.component == NoResult);
John Kessenich140f3df2015-06-26 16:58:36 -06002370
John Kessenich55e7d112015-11-15 21:33:39 -07002371 // 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 -06002372 // extract and insert elements to perform writeMask and/or swizzle.
John Kessenich5c3eed52018-02-05 14:44:14 -07002373 if (accessChain.swizzle.size() > 0) {
John Kessenich140f3df2015-06-26 16:58:36 -06002374 Id tempBaseId = createLoad(base);
John Kessenich5c3eed52018-02-05 14:44:14 -07002375 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
John Kessenich140f3df2015-06-26 16:58:36 -06002376 }
2377
John Kessenich140f3df2015-06-26 16:58:36 -06002378 createStore(source, base);
2379}
2380
2381// Comments in header
John Kessenich5611c6d2018-04-05 11:25:02 -06002382Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType)
John Kessenich140f3df2015-06-26 16:58:36 -06002383{
2384 Id id;
2385
2386 if (accessChain.isRValue) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002387 // transfer access chain, but try to stay in registers
John Kessenich55e7d112015-11-15 21:33:39 -07002388 transferAccessChainSwizzle(false);
John Kessenich140f3df2015-06-26 16:58:36 -06002389 if (accessChain.indexChain.size() > 0) {
John Kessenichfa668da2015-09-13 14:46:30 -06002390 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
John Kessenich32cfd492016-02-02 12:37:46 -07002391
John Kessenich140f3df2015-06-26 16:58:36 -06002392 // if all the accesses are constants, we can use OpCompositeExtract
2393 std::vector<unsigned> indexes;
2394 bool constant = true;
2395 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
2396 if (isConstantScalar(accessChain.indexChain[i]))
2397 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
2398 else {
2399 constant = false;
2400 break;
2401 }
2402 }
2403
2404 if (constant)
John Kessenichfa668da2015-09-13 14:46:30 -06002405 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06002406 else {
2407 // make a new function variable for this r-value
2408 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
2409
2410 // store into it
2411 createStore(accessChain.base, lValue);
2412
2413 // move base to the new variable
2414 accessChain.base = lValue;
2415 accessChain.isRValue = false;
2416
2417 // load through the access chain
2418 id = createLoad(collapseAccessChain());
2419 }
John Kessenich32cfd492016-02-02 12:37:46 -07002420 setPrecision(id, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002421 } else
John Kessenich32cfd492016-02-02 12:37:46 -07002422 id = accessChain.base; // no precision, it was set when this was defined
John Kessenich140f3df2015-06-26 16:58:36 -06002423 } else {
John Kessenich55e7d112015-11-15 21:33:39 -07002424 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002425 // load through the access chain
2426 id = createLoad(collapseAccessChain());
John Kessenich32cfd492016-02-02 12:37:46 -07002427 setPrecision(id, precision);
John Kessenich5611c6d2018-04-05 11:25:02 -06002428 addDecoration(id, nonUniform);
John Kessenich140f3df2015-06-26 16:58:36 -06002429 }
2430
2431 // Done, unless there are swizzles to do
John Kessenichfa668da2015-09-13 14:46:30 -06002432 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002433 return id;
2434
John Kessenich140f3df2015-06-26 16:58:36 -06002435 // Do remaining swizzling
John Kessenich5c3eed52018-02-05 14:44:14 -07002436
2437 // Do the basic swizzle
2438 if (accessChain.swizzle.size() > 0) {
John Kessenichfa668da2015-09-13 14:46:30 -06002439 Id swizzledType = getScalarTypeId(getTypeId(id));
John Kessenich140f3df2015-06-26 16:58:36 -06002440 if (accessChain.swizzle.size() > 1)
John Kessenichfa668da2015-09-13 14:46:30 -06002441 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
John Kessenich32cfd492016-02-02 12:37:46 -07002442 id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
John Kessenich140f3df2015-06-26 16:58:36 -06002443 }
2444
John Kessenich5c3eed52018-02-05 14:44:14 -07002445 // Do the dynamic component
John Kessenichfa668da2015-09-13 14:46:30 -06002446 if (accessChain.component != NoResult)
John Kessenich32cfd492016-02-02 12:37:46 -07002447 id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002448
John Kessenich5611c6d2018-04-05 11:25:02 -06002449 addDecoration(id, nonUniform);
John Kessenich140f3df2015-06-26 16:58:36 -06002450 return id;
2451}
2452
2453Id Builder::accessChainGetLValue()
2454{
2455 assert(accessChain.isRValue == false);
2456
John Kessenich55e7d112015-11-15 21:33:39 -07002457 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002458 Id lvalue = collapseAccessChain();
2459
2460 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
2461 // extract and insert elements to perform writeMask and/or swizzle. This does not
2462 // go with getting a direct l-value pointer.
2463 assert(accessChain.swizzle.size() == 0);
John Kessenichfa668da2015-09-13 14:46:30 -06002464 assert(accessChain.component == NoResult);
John Kessenich140f3df2015-06-26 16:58:36 -06002465
2466 return lvalue;
2467}
2468
John Kessenich103bef92016-02-08 21:38:15 -07002469// comment in header
2470Id Builder::accessChainGetInferredType()
2471{
2472 // anything to operate on?
2473 if (accessChain.base == NoResult)
2474 return NoType;
2475 Id type = getTypeId(accessChain.base);
2476
2477 // do initial dereference
2478 if (! accessChain.isRValue)
2479 type = getContainedTypeId(type);
2480
2481 // dereference each index
rdb32084e82016-02-23 22:17:38 +01002482 for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
John Kessenich103bef92016-02-08 21:38:15 -07002483 if (isStructType(type))
rdb32084e82016-02-23 22:17:38 +01002484 type = getContainedTypeId(type, getConstantScalar(*it));
John Kessenich103bef92016-02-08 21:38:15 -07002485 else
2486 type = getContainedTypeId(type);
2487 }
2488
2489 // dereference swizzle
2490 if (accessChain.swizzle.size() == 1)
2491 type = getContainedTypeId(type);
2492 else if (accessChain.swizzle.size() > 1)
baldurk227e0262016-02-10 19:41:29 +01002493 type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
John Kessenich103bef92016-02-08 21:38:15 -07002494
2495 // dereference component selection
2496 if (accessChain.component)
2497 type = getContainedTypeId(type);
2498
2499 return type;
2500}
2501
John Kessenich140f3df2015-06-26 16:58:36 -06002502void Builder::dump(std::vector<unsigned int>& out) const
2503{
2504 // Header, before first instructions:
2505 out.push_back(MagicNumber);
John Kessenich2b5ea9f2018-01-31 18:35:56 -07002506 out.push_back(spvVersion);
John Kessenich140f3df2015-06-26 16:58:36 -06002507 out.push_back(builderNumber);
2508 out.push_back(uniqueId + 1);
2509 out.push_back(0);
2510
John Kessenich55e7d112015-11-15 21:33:39 -07002511 // Capabilities
rdb32084e82016-02-23 22:17:38 +01002512 for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
John Kessenich55e7d112015-11-15 21:33:39 -07002513 Instruction capInst(0, 0, OpCapability);
rdb32084e82016-02-23 22:17:38 +01002514 capInst.addImmediateOperand(*it);
John Kessenich55e7d112015-11-15 21:33:39 -07002515 capInst.dump(out);
2516 }
2517
Rex Xu51596642016-09-21 18:56:12 +08002518 for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
Rex Xu9d93a232016-05-05 12:30:44 +08002519 Instruction extInst(0, 0, OpExtension);
Rex Xu430ef402016-10-14 17:22:23 +08002520 extInst.addStringOperand(it->c_str());
Rex Xu9d93a232016-05-05 12:30:44 +08002521 extInst.dump(out);
2522 }
John Kessenich55e7d112015-11-15 21:33:39 -07002523
2524 dumpInstructions(out, imports);
2525 Instruction memInst(0, 0, OpMemoryModel);
2526 memInst.addImmediateOperand(addressModel);
2527 memInst.addImmediateOperand(memoryModel);
2528 memInst.dump(out);
2529
2530 // Instructions saved up while building:
2531 dumpInstructions(out, entryPoints);
2532 dumpInstructions(out, executionModes);
2533
2534 // Debug instructions
John Kessenich121853f2017-05-31 17:11:16 -06002535 dumpInstructions(out, strings);
2536 dumpSourceInstructions(out);
Rex Xu9d93a232016-05-05 12:30:44 +08002537 for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
2538 Instruction sourceExtInst(0, 0, OpSourceExtension);
2539 sourceExtInst.addStringOperand(sourceExtensions[e]);
2540 sourceExtInst.dump(out);
John Kessenich140f3df2015-06-26 16:58:36 -06002541 }
John Kessenich140f3df2015-06-26 16:58:36 -06002542 dumpInstructions(out, names);
John Kessenich57f6a012018-02-22 19:36:18 -07002543 dumpModuleProcesses(out);
John Kessenich55e7d112015-11-15 21:33:39 -07002544
2545 // Annotation instructions
John Kessenich140f3df2015-06-26 16:58:36 -06002546 dumpInstructions(out, decorations);
John Kessenich55e7d112015-11-15 21:33:39 -07002547
John Kessenich140f3df2015-06-26 16:58:36 -06002548 dumpInstructions(out, constantsTypesGlobals);
2549 dumpInstructions(out, externals);
2550
2551 // The functions
2552 module.dump(out);
2553}
2554
2555//
2556// Protected methods.
2557//
2558
John Kessenich5c3eed52018-02-05 14:44:14 -07002559// Turn the described access chain in 'accessChain' into an instruction(s)
John Kessenich55e7d112015-11-15 21:33:39 -07002560// computing its address. This *cannot* include complex swizzles, which must
John Kessenich5c3eed52018-02-05 14:44:14 -07002561// be handled after this is called.
2562//
2563// Can generate code.
John Kessenich140f3df2015-06-26 16:58:36 -06002564Id Builder::collapseAccessChain()
2565{
John Kessenich140f3df2015-06-26 16:58:36 -06002566 assert(accessChain.isRValue == false);
2567
John Kessenich5c3eed52018-02-05 14:44:14 -07002568 // did we already emit an access chain for this?
2569 if (accessChain.instr != NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002570 return accessChain.instr;
John Kessenich5c3eed52018-02-05 14:44:14 -07002571
2572 // If we have a dynamic component, we can still transfer
2573 // that into a final operand to the access chain. We need to remap the
2574 // dynamic component through the swizzle to get a new dynamic component to
2575 // update.
2576 //
2577 // This was not done in transferAccessChainSwizzle() because it might
2578 // generate code.
2579 remapDynamicSwizzle();
2580 if (accessChain.component != NoResult) {
2581 // transfer the dynamic component to the access chain
2582 accessChain.indexChain.push_back(accessChain.component);
2583 accessChain.component = NoResult;
2584 }
2585
2586 // note that non-trivial swizzling is left pending
2587
2588 // do we have an access chain?
2589 if (accessChain.indexChain.size() == 0)
John Kessenich140f3df2015-06-26 16:58:36 -06002590 return accessChain.base;
John Kessenich55e7d112015-11-15 21:33:39 -07002591
John Kessenich5c3eed52018-02-05 14:44:14 -07002592 // emit the access chain
2593 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
2594 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
2595
2596 return accessChain.instr;
2597}
2598
2599// For a dynamic component selection of a swizzle.
2600//
2601// Turn the swizzle and dynamic component into just a dynamic component.
2602//
2603// Generates code.
2604void Builder::remapDynamicSwizzle()
2605{
2606 // do we have a swizzle to remap a dynamic component through?
2607 if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
2608 // build a vector of the swizzle for the component to map into
2609 std::vector<Id> components;
Daniel Kochbfe09522018-03-13 17:06:51 -04002610 for (int c = 0; c < (int)accessChain.swizzle.size(); ++c)
John Kessenich5c3eed52018-02-05 14:44:14 -07002611 components.push_back(makeUintConstant(accessChain.swizzle[c]));
2612 Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
2613 Id map = makeCompositeConstant(mapType, components);
2614
2615 // use it
2616 accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
2617 accessChain.swizzle.clear();
2618 }
John Kessenich140f3df2015-06-26 16:58:36 -06002619}
2620
John Kessenich55e7d112015-11-15 21:33:39 -07002621// clear out swizzle if it is redundant, that is reselecting the same components
2622// that would be present without the swizzle.
John Kessenich140f3df2015-06-26 16:58:36 -06002623void Builder::simplifyAccessChainSwizzle()
2624{
2625 // If the swizzle has fewer components than the vector, it is subsetting, and must stay
2626 // to preserve that fact.
John Kessenichfa668da2015-09-13 14:46:30 -06002627 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
John Kessenich140f3df2015-06-26 16:58:36 -06002628 return;
2629
2630 // if components are out of order, it is a swizzle
2631 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
2632 if (i != accessChain.swizzle[i])
2633 return;
2634 }
2635
2636 // otherwise, there is no need to track this swizzle
2637 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002638 if (accessChain.component == NoResult)
2639 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002640}
2641
John Kessenich55e7d112015-11-15 21:33:39 -07002642// To the extent any swizzling can become part of the chain
2643// of accesses instead of a post operation, make it so.
John Kessenich5c3eed52018-02-05 14:44:14 -07002644// If 'dynamic' is true, include transferring the dynamic component,
2645// otherwise, leave it pending.
John Kessenich55e7d112015-11-15 21:33:39 -07002646//
John Kessenich5c3eed52018-02-05 14:44:14 -07002647// Does not generate code. just updates the access chain.
John Kessenich55e7d112015-11-15 21:33:39 -07002648void Builder::transferAccessChainSwizzle(bool dynamic)
John Kessenich140f3df2015-06-26 16:58:36 -06002649{
John Kessenich55e7d112015-11-15 21:33:39 -07002650 // non existent?
2651 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002652 return;
2653
John Kessenich5c3eed52018-02-05 14:44:14 -07002654 // too complex?
2655 // (this requires either a swizzle, or generating code for a dynamic component)
2656 if (accessChain.swizzle.size() > 1)
John Kessenich55e7d112015-11-15 21:33:39 -07002657 return;
2658
John Kessenich5c3eed52018-02-05 14:44:14 -07002659 // single component, either in the swizzle and/or dynamic component
John Kessenich55e7d112015-11-15 21:33:39 -07002660 if (accessChain.swizzle.size() == 1) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002661 assert(accessChain.component == NoResult);
2662 // handle static component selection
John Kessenich140f3df2015-06-26 16:58:36 -06002663 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
John Kessenich55e7d112015-11-15 21:33:39 -07002664 accessChain.swizzle.clear();
John Kessenich55e7d112015-11-15 21:33:39 -07002665 accessChain.preSwizzleBaseType = NoType;
John Kessenich55e7d112015-11-15 21:33:39 -07002666 } else if (dynamic && accessChain.component != NoResult) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002667 assert(accessChain.swizzle.size() == 0);
John Kessenich55e7d112015-11-15 21:33:39 -07002668 // handle dynamic component
John Kessenich140f3df2015-06-26 16:58:36 -06002669 accessChain.indexChain.push_back(accessChain.component);
John Kessenich55e7d112015-11-15 21:33:39 -07002670 accessChain.preSwizzleBaseType = NoType;
2671 accessChain.component = NoResult;
2672 }
John Kessenich140f3df2015-06-26 16:58:36 -06002673}
2674
2675// Utility method for creating a new block and setting the insert point to
2676// be in it. This is useful for flow-control operations that need a "dummy"
2677// block proceeding them (e.g. instructions after a discard, etc).
2678void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
2679{
2680 Block* block = new Block(getUniqueId(), buildPoint->getParent());
2681 block->setUnreachable();
2682 buildPoint->getParent().addBlock(block);
2683 setBuildPoint(block);
2684
John Kessenich927608b2017-01-06 12:34:14 -07002685 // if (name)
John Kessenich140f3df2015-06-26 16:58:36 -06002686 // addName(block->getId(), name);
2687}
2688
2689// Comments in header
2690void Builder::createBranch(Block* block)
2691{
2692 Instruction* branch = new Instruction(OpBranch);
2693 branch->addIdOperand(block->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002694 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002695 block->addPredecessor(buildPoint);
2696}
2697
John Kessenich55e7d112015-11-15 21:33:39 -07002698void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
John Kessenich140f3df2015-06-26 16:58:36 -06002699{
John Kessenich55e7d112015-11-15 21:33:39 -07002700 Instruction* merge = new Instruction(OpSelectionMerge);
John Kessenich140f3df2015-06-26 16:58:36 -06002701 merge->addIdOperand(mergeBlock->getId());
2702 merge->addImmediateOperand(control);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002703 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich140f3df2015-06-26 16:58:36 -06002704}
2705
John Kessenicha2858d92018-01-31 08:11:18 -07002706void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
2707 unsigned int dependencyLength)
John Kessenich55e7d112015-11-15 21:33:39 -07002708{
2709 Instruction* merge = new Instruction(OpLoopMerge);
2710 merge->addIdOperand(mergeBlock->getId());
2711 merge->addIdOperand(continueBlock->getId());
2712 merge->addImmediateOperand(control);
John Kessenicha2858d92018-01-31 08:11:18 -07002713 if ((control & LoopControlDependencyLengthMask) != 0)
2714 merge->addImmediateOperand(dependencyLength);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002715 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich55e7d112015-11-15 21:33:39 -07002716}
2717
John Kessenich140f3df2015-06-26 16:58:36 -06002718void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
2719{
2720 Instruction* branch = new Instruction(OpBranchConditional);
2721 branch->addIdOperand(condition);
2722 branch->addIdOperand(thenBlock->getId());
2723 branch->addIdOperand(elseBlock->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002724 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002725 thenBlock->addPredecessor(buildPoint);
2726 elseBlock->addPredecessor(buildPoint);
2727}
2728
John Kessenich121853f2017-05-31 17:11:16 -06002729// OpSource
2730// [OpSourceContinued]
2731// ...
2732void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
2733{
2734 const int maxWordCount = 0xFFFF;
2735 const int opSourceWordCount = 4;
2736 const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
2737
2738 if (source != SourceLanguageUnknown) {
2739 // OpSource Language Version File Source
2740 Instruction sourceInst(NoResult, NoType, OpSource);
2741 sourceInst.addImmediateOperand(source);
2742 sourceInst.addImmediateOperand(sourceVersion);
2743 // File operand
2744 if (sourceFileStringId != NoResult) {
2745 sourceInst.addIdOperand(sourceFileStringId);
2746 // Source operand
2747 if (sourceText.size() > 0) {
2748 int nextByte = 0;
2749 std::string subString;
2750 while ((int)sourceText.size() - nextByte > 0) {
2751 subString = sourceText.substr(nextByte, nonNullBytesPerInstruction);
2752 if (nextByte == 0) {
2753 // OpSource
2754 sourceInst.addStringOperand(subString.c_str());
2755 sourceInst.dump(out);
2756 } else {
2757 // OpSourcContinued
2758 Instruction sourceContinuedInst(OpSourceContinued);
2759 sourceContinuedInst.addStringOperand(subString.c_str());
2760 sourceContinuedInst.dump(out);
2761 }
2762 nextByte += nonNullBytesPerInstruction;
2763 }
2764 } else
2765 sourceInst.dump(out);
2766 } else
2767 sourceInst.dump(out);
2768 }
2769}
2770
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002771void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
John Kessenich140f3df2015-06-26 16:58:36 -06002772{
2773 for (int i = 0; i < (int)instructions.size(); ++i) {
2774 instructions[i]->dump(out);
2775 }
2776}
2777
John Kessenich2a271162017-07-20 20:00:36 -06002778void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
2779{
2780 for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
John Kessenich2a271162017-07-20 20:00:36 -06002781 Instruction moduleProcessed(OpModuleProcessed);
2782 moduleProcessed.addStringOperand(moduleProcesses[i]);
2783 moduleProcessed.dump(out);
2784 }
2785}
2786
John Kessenich140f3df2015-06-26 16:58:36 -06002787}; // end spv namespace