blob: 237496e3b1942c66ededa4a1d9c1233558b9bcf5 [file] [log] [blame]
John Kessenich140f3df2015-06-26 16:58:36 -06001//
2//Copyright (C) 2014 LunarG, Inc.
3//
4//All rights reserved.
5//
6//Redistribution and use in source and binary forms, with or without
7//modification, are permitted provided that the following conditions
8//are met:
9//
10// Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//
13// Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following
15// disclaimer in the documentation and/or other materials provided
16// with the distribution.
17//
18// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19// contributors may be used to endorse or promote products derived
20// from this software without specific prior written permission.
21//
22//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33//POSSIBILITY OF SUCH DAMAGE.
34
35//
36// Author: John Kessenich, LunarG
37//
38
39//
40// Helper for making SPIR-V IR. Generally, this is documented in the header
41// SpvBuilder.h.
42//
43
44#include <assert.h>
45#include <stdio.h>
46#include <stdlib.h>
47
John Kessenich426394d2015-07-23 10:22:48 -060048#include <unordered_set>
49
John Kessenich140f3df2015-06-26 16:58:36 -060050#include "SpvBuilder.h"
51
52#ifndef _WIN32
53 #include <cstdio>
54#endif
55
56namespace spv {
57
John Kessenich55e7d112015-11-15 21:33:39 -070058Builder::Builder(unsigned int magicNumber) :
John Kessenich140f3df2015-06-26 16:58:36 -060059 source(SourceLanguageUnknown),
60 sourceVersion(0),
61 addressModel(AddressingModelLogical),
62 memoryModel(MemoryModelGLSL450),
John Kessenich55e7d112015-11-15 21:33:39 -070063 builderNumber(magicNumber),
John Kessenich140f3df2015-06-26 16:58:36 -060064 buildPoint(0),
65 uniqueId(0),
John Kesseniche770b3e2015-09-14 20:58:02 -060066 mainFunction(0)
John Kessenich140f3df2015-06-26 16:58:36 -060067{
68 clearAccessChain();
69}
70
71Builder::~Builder()
72{
73}
74
75Id Builder::import(const char* name)
76{
77 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
78 import->addStringOperand(name);
79
Andrew Woloszynb7946d12016-01-18 09:23:56 -050080 imports.push_back(std::unique_ptr<Instruction>(import));
John Kessenich140f3df2015-06-26 16:58:36 -060081 return import->getResultId();
82}
83
84// For creating new groupedTypes (will return old type if the requested one was already made).
85Id Builder::makeVoidType()
86{
87 Instruction* type;
88 if (groupedTypes[OpTypeVoid].size() == 0) {
89 type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
90 groupedTypes[OpTypeVoid].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -050091 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -060092 module.mapInstruction(type);
93 } else
94 type = groupedTypes[OpTypeVoid].back();
95
96 return type->getResultId();
97}
98
99Id Builder::makeBoolType()
100{
101 Instruction* type;
102 if (groupedTypes[OpTypeBool].size() == 0) {
103 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
104 groupedTypes[OpTypeBool].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500105 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600106 module.mapInstruction(type);
107 } else
108 type = groupedTypes[OpTypeBool].back();
109
110 return type->getResultId();
111}
112
John Kessenich55e7d112015-11-15 21:33:39 -0700113Id Builder::makeSamplerType()
114{
115 Instruction* type;
116 if (groupedTypes[OpTypeSampler].size() == 0) {
117 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
118 groupedTypes[OpTypeSampler].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500119 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich55e7d112015-11-15 21:33:39 -0700120 module.mapInstruction(type);
121 } else
122 type = groupedTypes[OpTypeSampler].back();
123
124 return type->getResultId();
125}
126
John Kessenich140f3df2015-06-26 16:58:36 -0600127Id Builder::makePointer(StorageClass storageClass, Id pointee)
128{
129 // try to find it
130 Instruction* type;
131 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
132 type = groupedTypes[OpTypePointer][t];
133 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
134 type->getIdOperand(1) == pointee)
135 return type->getResultId();
136 }
137
138 // not found, make it
139 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
140 type->addImmediateOperand(storageClass);
141 type->addIdOperand(pointee);
142 groupedTypes[OpTypePointer].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500143 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600144 module.mapInstruction(type);
145
146 return type->getResultId();
147}
148
149Id Builder::makeIntegerType(int width, bool hasSign)
150{
151 // try to find it
152 Instruction* type;
153 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
154 type = groupedTypes[OpTypeInt][t];
155 if (type->getImmediateOperand(0) == (unsigned)width &&
156 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
157 return type->getResultId();
158 }
159
160 // not found, make it
161 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
162 type->addImmediateOperand(width);
163 type->addImmediateOperand(hasSign ? 1 : 0);
164 groupedTypes[OpTypeInt].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500165 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600166 module.mapInstruction(type);
167
168 return type->getResultId();
169}
170
171Id Builder::makeFloatType(int width)
172{
173 // try to find it
174 Instruction* type;
175 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
176 type = groupedTypes[OpTypeFloat][t];
177 if (type->getImmediateOperand(0) == (unsigned)width)
178 return type->getResultId();
179 }
180
181 // not found, make it
182 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
183 type->addImmediateOperand(width);
184 groupedTypes[OpTypeFloat].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500185 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600186 module.mapInstruction(type);
187
188 return type->getResultId();
189}
190
John Kessenich55e7d112015-11-15 21:33:39 -0700191// Make a struct without checking for duplication.
192// See makeStructResultType() for non-decorated structs
193// needed as the result of some instructions, which does
194// check for duplicates.
John Kessenich140f3df2015-06-26 16:58:36 -0600195Id Builder::makeStructType(std::vector<Id>& members, const char* name)
196{
John Kessenich55e7d112015-11-15 21:33:39 -0700197 // Don't look for previous one, because in the general case,
198 // structs can be duplicated except for decorations.
199
John Kessenich140f3df2015-06-26 16:58:36 -0600200 // not found, make it
201 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
202 for (int op = 0; op < (int)members.size(); ++op)
203 type->addIdOperand(members[op]);
204 groupedTypes[OpTypeStruct].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500205 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600206 module.mapInstruction(type);
207 addName(type->getResultId(), name);
208
209 return type->getResultId();
210}
211
John Kessenich55e7d112015-11-15 21:33:39 -0700212// Make a struct for the simple results of several instructions,
213// checking for duplication.
214Id Builder::makeStructResultType(Id type0, Id type1)
215{
216 // try to find it
217 Instruction* type;
218 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
219 type = groupedTypes[OpTypeStruct][t];
220 if (type->getNumOperands() != 2)
221 continue;
222 if (type->getIdOperand(0) != type0 ||
223 type->getIdOperand(1) != type1)
224 continue;
225 return type->getResultId();
226 }
227
228 // not found, make it
229 std::vector<spv::Id> members;
230 members.push_back(type0);
231 members.push_back(type1);
232
233 return makeStructType(members, "ResType");
234}
235
John Kessenich140f3df2015-06-26 16:58:36 -0600236Id Builder::makeVectorType(Id component, int size)
237{
238 // try to find it
239 Instruction* type;
240 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
241 type = groupedTypes[OpTypeVector][t];
242 if (type->getIdOperand(0) == component &&
243 type->getImmediateOperand(1) == (unsigned)size)
244 return type->getResultId();
245 }
246
247 // not found, make it
248 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
249 type->addIdOperand(component);
250 type->addImmediateOperand(size);
251 groupedTypes[OpTypeVector].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500252 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600253 module.mapInstruction(type);
254
255 return type->getResultId();
256}
257
258Id Builder::makeMatrixType(Id component, int cols, int rows)
259{
260 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
261
262 Id column = makeVectorType(component, rows);
263
264 // try to find it
265 Instruction* type;
266 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
267 type = groupedTypes[OpTypeMatrix][t];
268 if (type->getIdOperand(0) == column &&
269 type->getImmediateOperand(1) == (unsigned)cols)
270 return type->getResultId();
271 }
272
273 // not found, make it
274 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
275 type->addIdOperand(column);
276 type->addImmediateOperand(cols);
277 groupedTypes[OpTypeMatrix].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500278 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600279 module.mapInstruction(type);
280
281 return type->getResultId();
282}
283
John Kessenichc9e0a422015-12-29 21:27:24 -0700284// TODO: performance: track arrays per stride
285// If a stride is supplied (non-zero) make an array.
286// If no stride (0), reuse previous array types.
287Id Builder::makeArrayType(Id element, unsigned size, int stride)
John Kessenich140f3df2015-06-26 16:58:36 -0600288{
289 // First, we need a constant instruction for the size
290 Id sizeId = makeUintConstant(size);
291
John Kessenich140f3df2015-06-26 16:58:36 -0600292 Instruction* type;
John Kessenichc9e0a422015-12-29 21:27:24 -0700293 if (stride == 0) {
294 // try to find existing type
295 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
296 type = groupedTypes[OpTypeArray][t];
297 if (type->getIdOperand(0) == element &&
298 type->getIdOperand(1) == sizeId)
299 return type->getResultId();
300 }
John Kessenich140f3df2015-06-26 16:58:36 -0600301 }
302
303 // not found, make it
304 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
305 type->addIdOperand(element);
306 type->addIdOperand(sizeId);
307 groupedTypes[OpTypeArray].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500308 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600309 module.mapInstruction(type);
310
311 return type->getResultId();
312}
313
John Kessenichc9a80832015-09-12 12:17:44 -0600314Id Builder::makeRuntimeArray(Id element)
315{
316 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
317 type->addIdOperand(element);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500318 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenichc9a80832015-09-12 12:17:44 -0600319 module.mapInstruction(type);
320
321 return type->getResultId();
322}
323
John Kessenich140f3df2015-06-26 16:58:36 -0600324Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
325{
326 // try to find it
327 Instruction* type;
328 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
329 type = groupedTypes[OpTypeFunction][t];
330 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
331 continue;
332 bool mismatch = false;
333 for (int p = 0; p < (int)paramTypes.size(); ++p) {
334 if (paramTypes[p] != type->getIdOperand(p + 1)) {
335 mismatch = true;
336 break;
337 }
338 }
339 if (! mismatch)
John Kessenichc9a80832015-09-12 12:17:44 -0600340 return type->getResultId();
John Kessenich140f3df2015-06-26 16:58:36 -0600341 }
342
343 // not found, make it
344 type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
345 type->addIdOperand(returnType);
346 for (int p = 0; p < (int)paramTypes.size(); ++p)
347 type->addIdOperand(paramTypes[p]);
348 groupedTypes[OpTypeFunction].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500349 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600350 module.mapInstruction(type);
351
352 return type->getResultId();
353}
354
John Kessenich5e4b1242015-08-06 22:53:06 -0600355Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
John Kessenich140f3df2015-06-26 16:58:36 -0600356{
357 // try to find it
358 Instruction* type;
John Kessenich5e4b1242015-08-06 22:53:06 -0600359 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
360 type = groupedTypes[OpTypeImage][t];
John Kessenich140f3df2015-06-26 16:58:36 -0600361 if (type->getIdOperand(0) == sampledType &&
362 type->getImmediateOperand(1) == (unsigned int)dim &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600363 type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
John Kessenich140f3df2015-06-26 16:58:36 -0600364 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600365 type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
366 type->getImmediateOperand(5) == sampled &&
367 type->getImmediateOperand(6) == (unsigned int)format)
John Kessenich140f3df2015-06-26 16:58:36 -0600368 return type->getResultId();
369 }
370
371 // not found, make it
John Kessenich5e4b1242015-08-06 22:53:06 -0600372 type = new Instruction(getUniqueId(), NoType, OpTypeImage);
John Kessenich140f3df2015-06-26 16:58:36 -0600373 type->addIdOperand(sampledType);
374 type->addImmediateOperand( dim);
John Kessenich5e4b1242015-08-06 22:53:06 -0600375 type->addImmediateOperand( depth ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600376 type->addImmediateOperand(arrayed ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600377 type->addImmediateOperand( ms ? 1 : 0);
John Kessenich5e4b1242015-08-06 22:53:06 -0600378 type->addImmediateOperand(sampled);
379 type->addImmediateOperand((unsigned int)format);
John Kessenich140f3df2015-06-26 16:58:36 -0600380
John Kessenich5e4b1242015-08-06 22:53:06 -0600381 groupedTypes[OpTypeImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500382 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich5e4b1242015-08-06 22:53:06 -0600383 module.mapInstruction(type);
384
385 return type->getResultId();
386}
387
388Id Builder::makeSampledImageType(Id imageType)
389{
390 // try to find it
391 Instruction* type;
392 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
393 type = groupedTypes[OpTypeSampledImage][t];
394 if (type->getIdOperand(0) == imageType)
395 return type->getResultId();
396 }
397
398 // not found, make it
399 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
400 type->addIdOperand(imageType);
401
402 groupedTypes[OpTypeSampledImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500403 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600404 module.mapInstruction(type);
405
406 return type->getResultId();
407}
408
409Id Builder::getDerefTypeId(Id resultId) const
410{
411 Id typeId = getTypeId(resultId);
412 assert(isPointerType(typeId));
413
414 return module.getInstruction(typeId)->getImmediateOperand(1);
415}
416
417Op Builder::getMostBasicTypeClass(Id typeId) const
418{
419 Instruction* instr = module.getInstruction(typeId);
420
421 Op typeClass = instr->getOpCode();
422 switch (typeClass)
423 {
424 case OpTypeVoid:
425 case OpTypeBool:
426 case OpTypeInt:
427 case OpTypeFloat:
428 case OpTypeStruct:
429 return typeClass;
430 case OpTypeVector:
431 case OpTypeMatrix:
432 case OpTypeArray:
433 case OpTypeRuntimeArray:
434 return getMostBasicTypeClass(instr->getIdOperand(0));
435 case OpTypePointer:
436 return getMostBasicTypeClass(instr->getIdOperand(1));
437 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700438 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600439 return OpTypeFloat;
440 }
441}
442
John Kessenich22118352015-12-21 20:54:09 -0700443int Builder::getNumTypeConstituents(Id typeId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600444{
445 Instruction* instr = module.getInstruction(typeId);
446
447 switch (instr->getOpCode())
448 {
449 case OpTypeBool:
450 case OpTypeInt:
451 case OpTypeFloat:
452 return 1;
453 case OpTypeVector:
454 case OpTypeMatrix:
John Kessenich22118352015-12-21 20:54:09 -0700455 case OpTypeArray:
John Kessenich140f3df2015-06-26 16:58:36 -0600456 return instr->getImmediateOperand(1);
John Kessenich22118352015-12-21 20:54:09 -0700457 case OpTypeStruct:
458 return instr->getNumOperands();
John Kessenich140f3df2015-06-26 16:58:36 -0600459 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700460 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600461 return 1;
462 }
463}
464
465// Return the lowest-level type of scalar that an homogeneous composite is made out of.
466// Typically, this is just to find out if something is made out of ints or floats.
467// However, it includes returning a structure, if say, it is an array of structure.
468Id Builder::getScalarTypeId(Id typeId) const
469{
470 Instruction* instr = module.getInstruction(typeId);
471
472 Op typeClass = instr->getOpCode();
473 switch (typeClass)
474 {
475 case OpTypeVoid:
476 case OpTypeBool:
477 case OpTypeInt:
478 case OpTypeFloat:
479 case OpTypeStruct:
480 return instr->getResultId();
481 case OpTypeVector:
482 case OpTypeMatrix:
483 case OpTypeArray:
484 case OpTypeRuntimeArray:
485 case OpTypePointer:
486 return getScalarTypeId(getContainedTypeId(typeId));
487 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700488 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600489 return NoResult;
490 }
491}
492
493// Return the type of 'member' of a composite.
494Id Builder::getContainedTypeId(Id typeId, int member) const
495{
496 Instruction* instr = module.getInstruction(typeId);
497
498 Op typeClass = instr->getOpCode();
499 switch (typeClass)
500 {
501 case OpTypeVector:
502 case OpTypeMatrix:
503 case OpTypeArray:
504 case OpTypeRuntimeArray:
505 return instr->getIdOperand(0);
506 case OpTypePointer:
507 return instr->getIdOperand(1);
508 case OpTypeStruct:
509 return instr->getIdOperand(member);
510 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700511 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600512 return NoResult;
513 }
514}
515
516// Return the immediately contained type of a given composite type.
517Id Builder::getContainedTypeId(Id typeId) const
518{
519 return getContainedTypeId(typeId, 0);
520}
521
522// See if a scalar constant of this type has already been created, so it
523// can be reused rather than duplicated. (Required by the specification).
John Kessenich55e7d112015-11-15 21:33:39 -0700524Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const
John Kessenich140f3df2015-06-26 16:58:36 -0600525{
526 Instruction* constant;
527 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
528 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700529 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600530 constant->getTypeId() == typeId &&
531 constant->getImmediateOperand(0) == value)
532 return constant->getResultId();
533 }
534
535 return 0;
536}
537
538// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').
John Kessenich55e7d112015-11-15 21:33:39 -0700539Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const
John Kessenich140f3df2015-06-26 16:58:36 -0600540{
541 Instruction* constant;
542 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
543 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700544 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600545 constant->getTypeId() == typeId &&
546 constant->getImmediateOperand(0) == v1 &&
547 constant->getImmediateOperand(1) == v2)
548 return constant->getResultId();
549 }
550
551 return 0;
552}
553
John Kessenichf685df82015-10-13 10:55:08 -0600554// Return true if consuming 'opcode' means consuming a constant.
555// "constant" here means after final transform to executable code,
556// the value consumed will be a constant, so includes specialization.
John Kessenich71631272015-10-13 10:39:19 -0600557bool Builder::isConstantOpCode(Op opcode) const
558{
559 switch (opcode) {
560 case OpUndef:
561 case OpConstantTrue:
562 case OpConstantFalse:
563 case OpConstant:
564 case OpConstantComposite:
565 case OpConstantSampler:
566 case OpConstantNull:
567 case OpSpecConstantTrue:
568 case OpSpecConstantFalse:
569 case OpSpecConstant:
570 case OpSpecConstantComposite:
571 case OpSpecConstantOp:
572 return true;
573 default:
574 return false;
575 }
576}
577
John Kessenich55e7d112015-11-15 21:33:39 -0700578Id Builder::makeBoolConstant(bool b, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600579{
580 Id typeId = makeBoolType();
581 Instruction* constant;
John Kessenich55e7d112015-11-15 21:33:39 -0700582 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
John Kessenich140f3df2015-06-26 16:58:36 -0600583
584 // See if we already made it
585 Id existing = 0;
586 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
587 constant = groupedConstants[OpTypeBool][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700588 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
John Kessenich140f3df2015-06-26 16:58:36 -0600589 existing = constant->getResultId();
590 }
591
592 if (existing)
593 return existing;
594
595 // Make it
John Kessenich55e7d112015-11-15 21:33:39 -0700596 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500597 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600598 groupedConstants[OpTypeBool].push_back(c);
599 module.mapInstruction(c);
600
601 return c->getResultId();
602}
603
John Kessenich55e7d112015-11-15 21:33:39 -0700604Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600605{
John Kessenich55e7d112015-11-15 21:33:39 -0700606 Op opcode = specConstant ? OpSpecConstant : OpConstant;
607 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
John Kessenich140f3df2015-06-26 16:58:36 -0600608 if (existing)
609 return existing;
610
John Kessenich55e7d112015-11-15 21:33:39 -0700611 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600612 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500613 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600614 groupedConstants[OpTypeInt].push_back(c);
615 module.mapInstruction(c);
616
617 return c->getResultId();
618}
619
John Kessenich55e7d112015-11-15 21:33:39 -0700620Id Builder::makeFloatConstant(float f, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600621{
John Kessenich55e7d112015-11-15 21:33:39 -0700622 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600623 Id typeId = makeFloatType(32);
624 unsigned value = *(unsigned int*)&f;
John Kessenich55e7d112015-11-15 21:33:39 -0700625 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
John Kessenich140f3df2015-06-26 16:58:36 -0600626 if (existing)
627 return existing;
628
John Kessenich55e7d112015-11-15 21:33:39 -0700629 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600630 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500631 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600632 groupedConstants[OpTypeFloat].push_back(c);
633 module.mapInstruction(c);
634
635 return c->getResultId();
636}
637
John Kessenich55e7d112015-11-15 21:33:39 -0700638Id Builder::makeDoubleConstant(double d, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600639{
John Kessenich55e7d112015-11-15 21:33:39 -0700640 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600641 Id typeId = makeFloatType(64);
642 unsigned long long value = *(unsigned long long*)&d;
643 unsigned op1 = value & 0xFFFFFFFF;
644 unsigned op2 = value >> 32;
John Kessenich55e7d112015-11-15 21:33:39 -0700645 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
John Kessenich140f3df2015-06-26 16:58:36 -0600646 if (existing)
647 return existing;
648
John Kessenich55e7d112015-11-15 21:33:39 -0700649 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600650 c->addImmediateOperand(op1);
651 c->addImmediateOperand(op2);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500652 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600653 groupedConstants[OpTypeFloat].push_back(c);
654 module.mapInstruction(c);
655
656 return c->getResultId();
657}
658
659Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
660{
661 Instruction* constant = 0;
662 bool found = false;
663 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
664 constant = groupedConstants[typeClass][i];
665
666 // same shape?
667 if (constant->getNumOperands() != (int)comps.size())
668 continue;
669
670 // same contents?
671 bool mismatch = false;
672 for (int op = 0; op < constant->getNumOperands(); ++op) {
673 if (constant->getIdOperand(op) != comps[op]) {
674 mismatch = true;
675 break;
676 }
677 }
678 if (! mismatch) {
679 found = true;
680 break;
681 }
682 }
683
684 return found ? constant->getResultId() : NoResult;
685}
686
687// Comments in header
688Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
689{
690 assert(typeId);
691 Op typeClass = getTypeClass(typeId);
692
693 switch (typeClass) {
694 case OpTypeVector:
695 case OpTypeArray:
696 case OpTypeStruct:
697 case OpTypeMatrix:
698 break;
699 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700700 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600701 return makeFloatConstant(0.0);
702 }
703
704 Id existing = findCompositeConstant(typeClass, members);
705 if (existing)
706 return existing;
707
708 Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);
709 for (int op = 0; op < (int)members.size(); ++op)
710 c->addIdOperand(members[op]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500711 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600712 groupedConstants[typeClass].push_back(c);
713 module.mapInstruction(c);
714
715 return c->getResultId();
716}
717
John Kessenich55e7d112015-11-15 21:33:39 -0700718Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600719{
720 Instruction* entryPoint = new Instruction(OpEntryPoint);
721 entryPoint->addImmediateOperand(model);
722 entryPoint->addIdOperand(function->getId());
John Kessenich5e4b1242015-08-06 22:53:06 -0600723 entryPoint->addStringOperand(name);
John Kessenich140f3df2015-06-26 16:58:36 -0600724
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500725 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
John Kessenich55e7d112015-11-15 21:33:39 -0700726
727 return entryPoint;
John Kessenich140f3df2015-06-26 16:58:36 -0600728}
729
John Kessenichb56a26a2015-09-16 16:04:05 -0600730// Currently relying on the fact that all 'value' of interest are small non-negative values.
731void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
John Kessenich140f3df2015-06-26 16:58:36 -0600732{
John Kessenich140f3df2015-06-26 16:58:36 -0600733 Instruction* instr = new Instruction(OpExecutionMode);
734 instr->addIdOperand(entryPoint->getId());
735 instr->addImmediateOperand(mode);
John Kessenichb56a26a2015-09-16 16:04:05 -0600736 if (value1 >= 0)
737 instr->addImmediateOperand(value1);
738 if (value2 >= 0)
739 instr->addImmediateOperand(value2);
740 if (value3 >= 0)
741 instr->addImmediateOperand(value3);
John Kessenich140f3df2015-06-26 16:58:36 -0600742
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500743 executionModes.push_back(std::unique_ptr<Instruction>(instr));
John Kessenich140f3df2015-06-26 16:58:36 -0600744}
745
746void Builder::addName(Id id, const char* string)
747{
748 Instruction* name = new Instruction(OpName);
749 name->addIdOperand(id);
750 name->addStringOperand(string);
751
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500752 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -0600753}
754
755void Builder::addMemberName(Id id, int memberNumber, const char* string)
756{
757 Instruction* name = new Instruction(OpMemberName);
758 name->addIdOperand(id);
759 name->addImmediateOperand(memberNumber);
760 name->addStringOperand(string);
761
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500762 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -0600763}
764
765void Builder::addLine(Id target, Id fileName, int lineNum, int column)
766{
767 Instruction* line = new Instruction(OpLine);
768 line->addIdOperand(target);
769 line->addIdOperand(fileName);
770 line->addImmediateOperand(lineNum);
771 line->addImmediateOperand(column);
772
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500773 lines.push_back(std::unique_ptr<Instruction>(line));
John Kessenich140f3df2015-06-26 16:58:36 -0600774}
775
776void Builder::addDecoration(Id id, Decoration decoration, int num)
777{
John Kessenich55e7d112015-11-15 21:33:39 -0700778 if (decoration == (spv::Decoration)spv::BadValue)
779 return;
John Kessenich140f3df2015-06-26 16:58:36 -0600780 Instruction* dec = new Instruction(OpDecorate);
781 dec->addIdOperand(id);
782 dec->addImmediateOperand(decoration);
783 if (num >= 0)
784 dec->addImmediateOperand(num);
785
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500786 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -0600787}
788
789void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
790{
791 Instruction* dec = new Instruction(OpMemberDecorate);
792 dec->addIdOperand(id);
793 dec->addImmediateOperand(member);
794 dec->addImmediateOperand(decoration);
795 if (num >= 0)
796 dec->addImmediateOperand(num);
797
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500798 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -0600799}
800
801// Comments in header
802Function* Builder::makeMain()
803{
804 assert(! mainFunction);
805
806 Block* entry;
807 std::vector<Id> params;
808
809 mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);
John Kessenich140f3df2015-06-26 16:58:36 -0600810
811 return mainFunction;
812}
813
814// Comments in header
John Kessenich140f3df2015-06-26 16:58:36 -0600815Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)
816{
817 Id typeId = makeFunctionType(returnType, paramTypes);
baldurkd76692d2015-07-12 11:32:58 +0200818 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
John Kessenich140f3df2015-06-26 16:58:36 -0600819 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
820
821 if (entry) {
822 *entry = new Block(getUniqueId(), *function);
823 function->addBlock(*entry);
824 setBuildPoint(*entry);
825 }
826
827 if (name)
828 addName(function->getId(), name);
829
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500830 functions.push_back(std::unique_ptr<Function>(function));
831
John Kessenich140f3df2015-06-26 16:58:36 -0600832 return function;
833}
834
835// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -0600836void Builder::makeReturn(bool implicit, Id retVal)
John Kessenich140f3df2015-06-26 16:58:36 -0600837{
John Kesseniche770b3e2015-09-14 20:58:02 -0600838 if (retVal) {
John Kessenich140f3df2015-06-26 16:58:36 -0600839 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
840 inst->addIdOperand(retVal);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500841 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -0600842 } else
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500843 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
John Kessenich140f3df2015-06-26 16:58:36 -0600844
845 if (! implicit)
846 createAndSetNoPredecessorBlock("post-return");
847}
848
849// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -0600850void Builder::leaveFunction()
John Kessenich140f3df2015-06-26 16:58:36 -0600851{
852 Block* block = buildPoint;
853 Function& function = buildPoint->getParent();
854 assert(block);
855
856 // If our function did not contain a return, add a return void now.
857 if (! block->isTerminated()) {
Dejan Mircevskied55bcd2016-01-19 21:13:38 -0500858 if (function.getReturnType() == makeVoidType())
859 makeReturn(true);
860 else {
861 makeReturn(true, createUndefined(function.getReturnType()));
John Kessenich140f3df2015-06-26 16:58:36 -0600862 }
863 }
John Kessenich140f3df2015-06-26 16:58:36 -0600864}
865
866// Comments in header
867void Builder::makeDiscard()
868{
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500869 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
John Kessenich140f3df2015-06-26 16:58:36 -0600870 createAndSetNoPredecessorBlock("post-discard");
871}
872
873// Comments in header
874Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
875{
876 Id pointerType = makePointer(storageClass, type);
877 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
878 inst->addImmediateOperand(storageClass);
879
880 switch (storageClass) {
John Kessenich140f3df2015-06-26 16:58:36 -0600881 case StorageClassFunction:
882 // Validation rules require the declaration in the entry block
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500883 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -0600884 break;
885
886 default:
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500887 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
John Kessenich55e7d112015-11-15 21:33:39 -0700888 module.mapInstruction(inst);
John Kessenich140f3df2015-06-26 16:58:36 -0600889 break;
890 }
891
892 if (name)
893 addName(inst->getResultId(), name);
894
895 return inst->getResultId();
896}
897
898// Comments in header
Miro Knejp28f9b1c2015-08-11 02:45:24 +0200899Id Builder::createUndefined(Id type)
900{
901 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500902 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
Miro Knejp28f9b1c2015-08-11 02:45:24 +0200903 return inst->getResultId();
904}
905
906// Comments in header
John Kessenich140f3df2015-06-26 16:58:36 -0600907void Builder::createStore(Id rValue, Id lValue)
908{
909 Instruction* store = new Instruction(OpStore);
910 store->addIdOperand(lValue);
911 store->addIdOperand(rValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500912 buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
John Kessenich140f3df2015-06-26 16:58:36 -0600913}
914
915// Comments in header
916Id Builder::createLoad(Id lValue)
917{
918 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
919 load->addIdOperand(lValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500920 buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
John Kessenich140f3df2015-06-26 16:58:36 -0600921
922 return load->getResultId();
923}
924
925// Comments in header
926Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)
927{
928 // Figure out the final resulting type.
929 spv::Id typeId = getTypeId(base);
930 assert(isPointerType(typeId) && offsets.size() > 0);
931 typeId = getContainedTypeId(typeId);
932 for (int i = 0; i < (int)offsets.size(); ++i) {
933 if (isStructType(typeId)) {
934 assert(isConstantScalar(offsets[i]));
935 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
936 } else
937 typeId = getContainedTypeId(typeId, offsets[i]);
938 }
939 typeId = makePointer(storageClass, typeId);
940
941 // Make the instruction
942 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
943 chain->addIdOperand(base);
944 for (int i = 0; i < (int)offsets.size(); ++i)
945 chain->addIdOperand(offsets[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500946 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
John Kessenich140f3df2015-06-26 16:58:36 -0600947
948 return chain->getResultId();
949}
950
John Kessenichee21fc92015-09-21 21:50:29 -0600951Id Builder::createArrayLength(Id base, unsigned int member)
952{
953 Instruction* length = new Instruction(getUniqueId(), makeIntType(32), OpArrayLength);
954 length->addIdOperand(base);
955 length->addImmediateOperand(member);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500956 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
John Kessenichee21fc92015-09-21 21:50:29 -0600957
958 return length->getResultId();
959}
960
John Kessenich140f3df2015-06-26 16:58:36 -0600961Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
962{
963 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
964 extract->addIdOperand(composite);
965 extract->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500966 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -0600967
968 return extract->getResultId();
969}
970
971Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)
972{
973 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
974 extract->addIdOperand(composite);
975 for (int i = 0; i < (int)indexes.size(); ++i)
976 extract->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500977 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -0600978
979 return extract->getResultId();
980}
981
982Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
983{
984 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
985 insert->addIdOperand(object);
986 insert->addIdOperand(composite);
987 insert->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500988 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -0600989
990 return insert->getResultId();
991}
992
993Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)
994{
995 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
996 insert->addIdOperand(object);
997 insert->addIdOperand(composite);
998 for (int i = 0; i < (int)indexes.size(); ++i)
999 insert->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001000 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001001
1002 return insert->getResultId();
1003}
1004
1005Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
1006{
1007 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
1008 extract->addIdOperand(vector);
1009 extract->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001010 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001011
1012 return extract->getResultId();
1013}
1014
1015Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
1016{
1017 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
1018 insert->addIdOperand(vector);
1019 insert->addIdOperand(component);
1020 insert->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001021 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001022
1023 return insert->getResultId();
1024}
1025
1026// An opcode that has no operands, no result id, and no type
1027void Builder::createNoResultOp(Op opCode)
1028{
1029 Instruction* op = new Instruction(opCode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001030 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001031}
1032
1033// An opcode that has one operand, no result id, and no type
1034void Builder::createNoResultOp(Op opCode, Id operand)
1035{
1036 Instruction* op = new Instruction(opCode);
1037 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001038 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001039}
1040
Rex Xufc618912015-09-09 16:42:49 +08001041// An opcode that has one operand, no result id, and no type
1042void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
1043{
1044 Instruction* op = new Instruction(opCode);
1045 for (auto operand : operands)
1046 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001047 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
Rex Xufc618912015-09-09 16:42:49 +08001048}
1049
John Kessenich5e4b1242015-08-06 22:53:06 -06001050void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
John Kessenich140f3df2015-06-26 16:58:36 -06001051{
1052 Instruction* op = new Instruction(OpControlBarrier);
John Kessenich5e4b1242015-08-06 22:53:06 -06001053 op->addImmediateOperand(makeUintConstant(execution));
1054 op->addImmediateOperand(makeUintConstant(memory));
1055 op->addImmediateOperand(makeUintConstant(semantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001056 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001057}
1058
1059void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
1060{
1061 Instruction* op = new Instruction(OpMemoryBarrier);
John Kessenich5e4b1242015-08-06 22:53:06 -06001062 op->addImmediateOperand(makeUintConstant(executionScope));
1063 op->addImmediateOperand(makeUintConstant(memorySemantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001064 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001065}
1066
1067// An opcode that has one operands, a result id, and a type
1068Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
1069{
1070 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1071 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001072 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001073
1074 return op->getResultId();
1075}
1076
1077Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
1078{
1079 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1080 op->addIdOperand(left);
1081 op->addIdOperand(right);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001082 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001083
1084 return op->getResultId();
1085}
1086
1087Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
1088{
1089 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1090 op->addIdOperand(op1);
1091 op->addIdOperand(op2);
1092 op->addIdOperand(op3);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001093 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001094
1095 return op->getResultId();
1096}
1097
John Kessenich5e4b1242015-08-06 22:53:06 -06001098Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
John Kessenich140f3df2015-06-26 16:58:36 -06001099{
1100 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
John Kessenich426394d2015-07-23 10:22:48 -06001101 for (auto operand : operands)
1102 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001103 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001104
1105 return op->getResultId();
1106}
1107
1108Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)
1109{
1110 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
1111 op->addIdOperand(function->getId());
1112 for (int a = 0; a < (int)args.size(); ++a)
1113 op->addIdOperand(args[a]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001114 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001115
1116 return op->getResultId();
1117}
1118
1119// Comments in header
1120Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)
1121{
1122 if (channels.size() == 1)
1123 return createCompositeExtract(source, typeId, channels.front());
1124
1125 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1126 assert(isVector(source));
1127 swizzle->addIdOperand(source);
1128 swizzle->addIdOperand(source);
1129 for (int i = 0; i < (int)channels.size(); ++i)
1130 swizzle->addImmediateOperand(channels[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001131 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001132
1133 return swizzle->getResultId();
1134}
1135
1136// Comments in header
1137Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)
1138{
John Kessenich30669532015-08-06 22:02:24 -06001139 assert(getNumComponents(source) == (int)channels.size());
John Kessenich140f3df2015-06-26 16:58:36 -06001140 if (channels.size() == 1 && getNumComponents(source) == 1)
1141 return createCompositeInsert(source, target, typeId, channels.front());
1142
1143 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1144 assert(isVector(source));
1145 assert(isVector(target));
1146 swizzle->addIdOperand(target);
1147 swizzle->addIdOperand(source);
1148
1149 // Set up an identity shuffle from the base value to the result value
1150 unsigned int components[4];
1151 int numTargetComponents = getNumComponents(target);
1152 for (int i = 0; i < numTargetComponents; ++i)
1153 components[i] = i;
1154
1155 // Punch in the l-value swizzle
1156 for (int i = 0; i < (int)channels.size(); ++i)
1157 components[channels[i]] = numTargetComponents + i;
1158
1159 // finish the instruction with these components selectors
1160 for (int i = 0; i < numTargetComponents; ++i)
1161 swizzle->addImmediateOperand(components[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001162 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001163
1164 return swizzle->getResultId();
1165}
1166
1167// Comments in header
1168void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
1169{
1170 int direction = getNumComponents(right) - getNumComponents(left);
1171
1172 if (direction > 0)
John Kessenich76f71392015-12-09 19:08:42 -07001173 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
John Kessenich140f3df2015-06-26 16:58:36 -06001174 else if (direction < 0)
John Kessenich76f71392015-12-09 19:08:42 -07001175 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
John Kessenich140f3df2015-06-26 16:58:36 -06001176
1177 return;
1178}
1179
1180// Comments in header
1181Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)
1182{
1183 assert(getNumComponents(scalar) == 1);
John Kessenich76f71392015-12-09 19:08:42 -07001184 assert(getTypeId(scalar) == getScalarTypeId(vectorType));
John Kessenich140f3df2015-06-26 16:58:36 -06001185
1186 int numComponents = getNumTypeComponents(vectorType);
1187 if (numComponents == 1)
1188 return scalar;
1189
1190 Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
1191 for (int c = 0; c < numComponents; ++c)
1192 smear->addIdOperand(scalar);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001193 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
John Kessenich140f3df2015-06-26 16:58:36 -06001194
1195 return smear->getResultId();
1196}
1197
1198// Comments in header
1199Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
1200{
1201 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
1202 inst->addIdOperand(builtins);
1203 inst->addImmediateOperand(entryPoint);
1204 for (int arg = 0; arg < (int)args.size(); ++arg)
1205 inst->addIdOperand(args[arg]);
1206
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001207 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -06001208 return inst->getResultId();
1209}
1210
1211// Accept all parameters needed to create a texture instruction.
1212// Create the correct instruction based on the inputs, and make the call.
Rex Xu48edadf2015-12-31 16:11:41 +08001213Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, const TextureParameters& parameters)
John Kessenich140f3df2015-06-26 16:58:36 -06001214{
John Kessenich5e4b1242015-08-06 22:53:06 -06001215 static const int maxTextureArgs = 10;
John Kessenich140f3df2015-06-26 16:58:36 -06001216 Id texArgs[maxTextureArgs] = {};
1217
1218 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001219 // Set up the fixed arguments
John Kessenich140f3df2015-06-26 16:58:36 -06001220 //
John Kessenich140f3df2015-06-26 16:58:36 -06001221 int numArgs = 0;
John Kessenich5e4b1242015-08-06 22:53:06 -06001222 bool xplicit = false;
John Kessenich140f3df2015-06-26 16:58:36 -06001223 texArgs[numArgs++] = parameters.sampler;
1224 texArgs[numArgs++] = parameters.coords;
John Kessenich140f3df2015-06-26 16:58:36 -06001225 if (parameters.Dref)
1226 texArgs[numArgs++] = parameters.Dref;
John Kessenich55e7d112015-11-15 21:33:39 -07001227 if (parameters.comp)
1228 texArgs[numArgs++] = parameters.comp;
John Kessenich140f3df2015-06-26 16:58:36 -06001229
1230 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001231 // Set up the optional arguments
1232 //
1233 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
1234 ++numArgs; // speculatively make room for the mask operand
1235 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
1236 if (parameters.bias) {
1237 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
1238 texArgs[numArgs++] = parameters.bias;
1239 }
1240 if (parameters.lod) {
1241 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1242 texArgs[numArgs++] = parameters.lod;
1243 xplicit = true;
1244 }
1245 if (parameters.gradX) {
1246 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
1247 texArgs[numArgs++] = parameters.gradX;
1248 texArgs[numArgs++] = parameters.gradY;
1249 xplicit = true;
1250 }
1251 if (parameters.offset) {
Rex Xu86e60812015-10-11 19:37:48 +08001252 if (isConstant(parameters.offset))
1253 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
1254 else
1255 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
John Kessenich5e4b1242015-08-06 22:53:06 -06001256 texArgs[numArgs++] = parameters.offset;
1257 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001258 if (parameters.offsets) {
1259 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
1260 texArgs[numArgs++] = parameters.offsets;
1261 }
1262 if (parameters.sample) {
1263 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
1264 texArgs[numArgs++] = parameters.sample;
1265 }
Rex Xu48edadf2015-12-31 16:11:41 +08001266 if (parameters.lodClamp) {
1267 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
1268 texArgs[numArgs++] = parameters.lodClamp;
1269 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001270 if (mask == ImageOperandsMaskNone)
1271 --numArgs; // undo speculative reservation for the mask argument
1272 else
1273 texArgs[optArgNum] = mask;
1274
1275 //
John Kessenich140f3df2015-06-26 16:58:36 -06001276 // Set up the instruction
1277 //
John Kessenich140f3df2015-06-26 16:58:36 -06001278 Op opCode;
John Kessenich5e4b1242015-08-06 22:53:06 -06001279 opCode = OpImageSampleImplicitLod;
Jason Ekstrand18b9fbd2015-09-05 14:14:48 -07001280 if (fetch) {
Rex Xu48edadf2015-12-31 16:11:41 +08001281 if (sparse)
1282 opCode = OpImageSparseFetch;
1283 else
1284 opCode = OpImageFetch;
John Kessenich55e7d112015-11-15 21:33:39 -07001285 } else if (gather) {
1286 if (parameters.Dref)
Rex Xu48edadf2015-12-31 16:11:41 +08001287 if (sparse)
1288 opCode = OpImageSparseDrefGather;
1289 else
1290 opCode = OpImageDrefGather;
John Kessenich55e7d112015-11-15 21:33:39 -07001291 else
Rex Xu48edadf2015-12-31 16:11:41 +08001292 if (sparse)
1293 opCode = OpImageSparseGather;
1294 else
1295 opCode = OpImageGather;
Jason Ekstrand18b9fbd2015-09-05 14:14:48 -07001296 } else if (xplicit) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001297 if (parameters.Dref) {
1298 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001299 if (sparse)
1300 opCode = OpImageSparseSampleProjDrefExplicitLod;
1301 else
1302 opCode = OpImageSampleProjDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001303 else
Rex Xu48edadf2015-12-31 16:11:41 +08001304 if (sparse)
1305 opCode = OpImageSparseSampleDrefExplicitLod;
1306 else
1307 opCode = OpImageSampleDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001308 } else {
1309 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001310 if (sparse)
1311 opCode = OpImageSparseSampleProjExplicitLod;
1312 else
1313 opCode = OpImageSampleProjExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001314 else
Rex Xu48edadf2015-12-31 16:11:41 +08001315 if (sparse)
1316 opCode = OpImageSparseSampleExplicitLod;
1317 else
1318 opCode = OpImageSampleExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001319 }
1320 } else {
1321 if (parameters.Dref) {
1322 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001323 if (sparse)
1324 opCode = OpImageSparseSampleProjDrefImplicitLod;
1325 else
1326 opCode = OpImageSampleProjDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001327 else
Rex Xu48edadf2015-12-31 16:11:41 +08001328 if (sparse)
1329 opCode = OpImageSparseSampleDrefImplicitLod;
1330 else
1331 opCode = OpImageSampleDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001332 } else {
1333 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001334 if (sparse)
1335 opCode = OpImageSparseSampleProjImplicitLod;
1336 else
1337 opCode = OpImageSampleProjImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001338 else
Rex Xu48edadf2015-12-31 16:11:41 +08001339 if (sparse)
1340 opCode = OpImageSparseSampleImplicitLod;
1341 else
1342 opCode = OpImageSampleImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001343 }
1344 }
John Kessenich140f3df2015-06-26 16:58:36 -06001345
John Kessenich7355eeb2015-09-14 22:08:12 -06001346 // See if the result type is expecting a smeared result.
1347 // This happens when a legacy shadow*() call is made, which
1348 // gets a vec4 back instead of a float.
1349 Id smearedType = resultType;
1350 if (! isScalarType(resultType)) {
1351 switch (opCode) {
1352 case OpImageSampleDrefImplicitLod:
1353 case OpImageSampleDrefExplicitLod:
1354 case OpImageSampleProjDrefImplicitLod:
1355 case OpImageSampleProjDrefExplicitLod:
1356 resultType = getScalarTypeId(resultType);
1357 break;
1358 default:
1359 break;
1360 }
1361 }
1362
Rex Xu48edadf2015-12-31 16:11:41 +08001363 Id typeId0 = 0;
1364 Id typeId1 = 0;
1365
1366 if (sparse) {
1367 typeId0 = resultType;
1368 typeId1 = getDerefTypeId(parameters.texelOut);
1369 resultType = makeStructResultType(typeId0, typeId1);
1370 }
1371
John Kessenich55e7d112015-11-15 21:33:39 -07001372 // Build the SPIR-V instruction
John Kessenich140f3df2015-06-26 16:58:36 -06001373 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
John Kessenich5e4b1242015-08-06 22:53:06 -06001374 for (int op = 0; op < optArgNum; ++op)
1375 textureInst->addIdOperand(texArgs[op]);
1376 if (optArgNum < numArgs)
1377 textureInst->addImmediateOperand(texArgs[optArgNum]);
1378 for (int op = optArgNum + 1; op < numArgs; ++op)
John Kessenich140f3df2015-06-26 16:58:36 -06001379 textureInst->addIdOperand(texArgs[op]);
1380 setPrecision(textureInst->getResultId(), precision);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001381 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
John Kessenich140f3df2015-06-26 16:58:36 -06001382
John Kessenich7355eeb2015-09-14 22:08:12 -06001383 Id resultId = textureInst->getResultId();
1384
Rex Xu48edadf2015-12-31 16:11:41 +08001385 if (sparse) {
1386 // Decode the return type that was a special structure
1387 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
1388 resultId = createCompositeExtract(resultId, typeId0, 0);
1389 } else {
1390 // When a smear is needed, do it, as per what was computed
1391 // above when resultType was changed to a scalar type.
1392 if (resultType != smearedType)
1393 resultId = smearScalar(precision, resultId, smearedType);
1394 }
John Kessenich7355eeb2015-09-14 22:08:12 -06001395
1396 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001397}
1398
1399// Comments in header
1400Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)
1401{
1402 // Figure out the result type
John Kessenich5e4b1242015-08-06 22:53:06 -06001403 Id resultType = 0;
John Kessenich140f3df2015-06-26 16:58:36 -06001404 switch (opCode) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001405 case OpImageQuerySize:
1406 case OpImageQuerySizeLod:
John Kessenich140f3df2015-06-26 16:58:36 -06001407 {
Mark Adams364c21c2016-01-06 13:41:02 -05001408 int numComponents = 0;
John Kessenich5e4b1242015-08-06 22:53:06 -06001409 switch (getTypeDimensionality(getImageType(parameters.sampler))) {
John Kessenich140f3df2015-06-26 16:58:36 -06001410 case Dim1D:
1411 case DimBuffer:
1412 numComponents = 1;
1413 break;
1414 case Dim2D:
1415 case DimCube:
1416 case DimRect:
John Kessenich50e57562015-12-21 21:21:11 -07001417 case DimSubpassData:
John Kessenich140f3df2015-06-26 16:58:36 -06001418 numComponents = 2;
1419 break;
1420 case Dim3D:
1421 numComponents = 3;
1422 break;
John Kessenich55e7d112015-11-15 21:33:39 -07001423
John Kessenich140f3df2015-06-26 16:58:36 -06001424 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001425 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -06001426 break;
1427 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001428 if (isArrayedImageType(getImageType(parameters.sampler)))
John Kessenich140f3df2015-06-26 16:58:36 -06001429 ++numComponents;
1430 if (numComponents == 1)
1431 resultType = makeIntType(32);
1432 else
1433 resultType = makeVectorType(makeIntType(32), numComponents);
1434
1435 break;
1436 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001437 case OpImageQueryLod:
John Kessenich140f3df2015-06-26 16:58:36 -06001438 resultType = makeVectorType(makeFloatType(32), 2);
1439 break;
John Kessenich5e4b1242015-08-06 22:53:06 -06001440 case OpImageQueryLevels:
1441 case OpImageQuerySamples:
John Kessenich140f3df2015-06-26 16:58:36 -06001442 resultType = makeIntType(32);
1443 break;
1444 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001445 assert(0);
1446 break;
John Kessenich140f3df2015-06-26 16:58:36 -06001447 }
1448
1449 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
1450 query->addIdOperand(parameters.sampler);
1451 if (parameters.coords)
1452 query->addIdOperand(parameters.coords);
1453 if (parameters.lod)
1454 query->addIdOperand(parameters.lod);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001455 buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
John Kessenich140f3df2015-06-26 16:58:36 -06001456
1457 return query->getResultId();
1458}
1459
John Kessenich22118352015-12-21 20:54:09 -07001460// External comments in header.
1461// Operates recursively to visit the composite's hierarchy.
1462Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
John Kessenich140f3df2015-06-26 16:58:36 -06001463{
1464 Id boolType = makeBoolType();
1465 Id valueType = getTypeId(value1);
1466
Mark Adamsd5ac5382016-02-01 19:13:06 -08001467 Id resultId = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001468
John Kessenich22118352015-12-21 20:54:09 -07001469 int numConstituents = getNumTypeConstituents(valueType);
John Kessenich140f3df2015-06-26 16:58:36 -06001470
John Kessenich22118352015-12-21 20:54:09 -07001471 // Scalars and Vectors
1472
1473 if (isScalarType(valueType) || isVectorType(valueType)) {
John Kesseniche23c9842016-01-04 23:49:03 -07001474 assert(valueType == getTypeId(value2));
John Kessenich22118352015-12-21 20:54:09 -07001475 // These just need a single comparison, just have
1476 // to figure out what it is.
John Kessenich140f3df2015-06-26 16:58:36 -06001477 Op op;
John Kessenich22118352015-12-21 20:54:09 -07001478 switch (getMostBasicTypeClass(valueType)) {
1479 case OpTypeFloat:
John Kessenich140f3df2015-06-26 16:58:36 -06001480 op = equal ? OpFOrdEqual : OpFOrdNotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001481 break;
1482 case OpTypeInt:
Mark Adamsd5ac5382016-02-01 19:13:06 -08001483 default:
John Kessenich140f3df2015-06-26 16:58:36 -06001484 op = equal ? OpIEqual : OpINotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001485 break;
1486 case OpTypeBool:
1487 op = equal ? OpLogicalEqual : OpLogicalNotEqual;
1488 precision = NoPrecision;
1489 break;
1490 }
John Kessenich140f3df2015-06-26 16:58:36 -06001491
John Kessenich22118352015-12-21 20:54:09 -07001492 if (isScalarType(valueType)) {
1493 // scalar
1494 resultId = createBinOp(op, boolType, value1, value2);
1495 setPrecision(resultId, precision);
1496 } else {
1497 // vector
1498 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
1499 setPrecision(resultId, precision);
1500 // reduce vector compares...
1501 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
1502 }
John Kessenich140f3df2015-06-26 16:58:36 -06001503
John Kessenich22118352015-12-21 20:54:09 -07001504 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001505 }
1506
John Kessenich22118352015-12-21 20:54:09 -07001507 // Only structs, arrays, and matrices should be left.
1508 // They share in common the reduction operation across their constituents.
1509 assert(isAggregateType(valueType) || isMatrixType(valueType));
John Kessenich140f3df2015-06-26 16:58:36 -06001510
John Kessenich22118352015-12-21 20:54:09 -07001511 // Compare each pair of constituents
1512 for (int constituent = 0; constituent < numConstituents; ++constituent) {
1513 std::vector<unsigned> indexes(1, constituent);
John Kesseniche23c9842016-01-04 23:49:03 -07001514 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
1515 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
1516 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
1517 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06001518
John Kessenich22118352015-12-21 20:54:09 -07001519 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
John Kessenich140f3df2015-06-26 16:58:36 -06001520
John Kessenich22118352015-12-21 20:54:09 -07001521 if (constituent == 0)
1522 resultId = subResultId;
1523 else
1524 resultId = createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId);
1525 }
John Kessenich140f3df2015-06-26 16:58:36 -06001526
John Kessenich22118352015-12-21 20:54:09 -07001527 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001528}
1529
John Kessenich140f3df2015-06-26 16:58:36 -06001530// OpCompositeConstruct
1531Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)
1532{
John Kessenich22118352015-12-21 20:54:09 -07001533 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size()));
John Kessenich140f3df2015-06-26 16:58:36 -06001534
1535 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
1536 for (int c = 0; c < (int)constituents.size(); ++c)
1537 op->addIdOperand(constituents[c]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001538 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001539
1540 return op->getResultId();
1541}
1542
1543// Vector or scalar constructor
1544Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1545{
1546 Id result = 0;
1547 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
1548 unsigned int targetComponent = 0;
1549
1550 // Special case: when calling a vector constructor with a single scalar
1551 // argument, smear the scalar
1552 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
1553 return smearScalar(precision, sources[0], resultTypeId);
1554
1555 Id scalarTypeId = getScalarTypeId(resultTypeId);
1556 std::vector<Id> constituents; // accumulate the arguments for OpCompositeConstruct
1557 for (unsigned int i = 0; i < sources.size(); ++i) {
John Kessenich55e7d112015-11-15 21:33:39 -07001558 assert(! isAggregate(sources[i]));
John Kessenich140f3df2015-06-26 16:58:36 -06001559 unsigned int sourceSize = getNumComponents(sources[i]);
John Kessenich140f3df2015-06-26 16:58:36 -06001560 unsigned int sourcesToUse = sourceSize;
1561 if (sourcesToUse + targetComponent > numTargetComponents)
1562 sourcesToUse = numTargetComponents - targetComponent;
1563
1564 for (unsigned int s = 0; s < sourcesToUse; ++s) {
1565 Id arg = sources[i];
1566 if (sourceSize > 1) {
1567 std::vector<unsigned> swiz;
1568 swiz.push_back(s);
1569 arg = createRvalueSwizzle(scalarTypeId, arg, swiz);
1570 }
1571
1572 if (numTargetComponents > 1)
1573 constituents.push_back(arg);
1574 else
1575 result = arg;
1576 ++targetComponent;
1577 }
1578
1579 if (targetComponent >= numTargetComponents)
1580 break;
1581 }
1582
1583 if (constituents.size() > 0)
1584 result = createCompositeConstruct(resultTypeId, constituents);
1585
1586 setPrecision(result, precision);
1587
1588 return result;
1589}
1590
1591// Comments in header
1592Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1593{
1594 Id componentTypeId = getScalarTypeId(resultTypeId);
1595 int numCols = getTypeNumColumns(resultTypeId);
1596 int numRows = getTypeNumRows(resultTypeId);
1597
1598 // Will use a two step process
1599 // 1. make a compile-time 2D array of values
1600 // 2. construct a matrix from that array
1601
1602 // Step 1.
1603
1604 // initialize the array to the identity matrix
1605 Id ids[maxMatrixSize][maxMatrixSize];
1606 Id one = makeFloatConstant(1.0);
1607 Id zero = makeFloatConstant(0.0);
1608 for (int col = 0; col < 4; ++col) {
1609 for (int row = 0; row < 4; ++row) {
1610 if (col == row)
1611 ids[col][row] = one;
1612 else
1613 ids[col][row] = zero;
1614 }
1615 }
1616
1617 // modify components as dictated by the arguments
1618 if (sources.size() == 1 && isScalar(sources[0])) {
1619 // a single scalar; resets the diagonals
1620 for (int col = 0; col < 4; ++col)
1621 ids[col][col] = sources[0];
1622 } else if (isMatrix(sources[0])) {
1623 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
1624 Id matrix = sources[0];
1625 int minCols = std::min(numCols, getNumColumns(matrix));
1626 int minRows = std::min(numRows, getNumRows(matrix));
1627 for (int col = 0; col < minCols; ++col) {
1628 std::vector<unsigned> indexes;
1629 indexes.push_back(col);
1630 for (int row = 0; row < minRows; ++row) {
1631 indexes.push_back(row);
1632 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
1633 indexes.pop_back();
1634 setPrecision(ids[col][row], precision);
1635 }
1636 }
1637 } else {
1638 // fill in the matrix in column-major order with whatever argument components are available
1639 int row = 0;
1640 int col = 0;
1641
1642 for (int arg = 0; arg < (int)sources.size(); ++arg) {
1643 Id argComp = sources[arg];
1644 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
1645 if (getNumComponents(sources[arg]) > 1) {
1646 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
1647 setPrecision(argComp, precision);
1648 }
1649 ids[col][row++] = argComp;
1650 if (row == numRows) {
1651 row = 0;
1652 col++;
1653 }
1654 }
1655 }
1656 }
1657
1658
1659 // Step 2: Construct a matrix from that array.
1660 // First make the column vectors, then make the matrix.
1661
1662 // make the column vectors
1663 Id columnTypeId = getContainedTypeId(resultTypeId);
1664 std::vector<Id> matrixColumns;
1665 for (int col = 0; col < numCols; ++col) {
1666 std::vector<Id> vectorComponents;
1667 for (int row = 0; row < numRows; ++row)
1668 vectorComponents.push_back(ids[col][row]);
1669 matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));
1670 }
1671
1672 // make the matrix
1673 return createCompositeConstruct(resultTypeId, matrixColumns);
1674}
1675
1676// Comments in header
1677Builder::If::If(Id cond, Builder& gb) :
1678 builder(gb),
1679 condition(cond),
1680 elseBlock(0)
1681{
1682 function = &builder.getBuildPoint()->getParent();
1683
1684 // make the blocks, but only put the then-block into the function,
1685 // the else-block and merge-block will be added later, in order, after
1686 // earlier code is emitted
1687 thenBlock = new Block(builder.getUniqueId(), *function);
1688 mergeBlock = new Block(builder.getUniqueId(), *function);
1689
1690 // Save the current block, so that we can add in the flow control split when
1691 // makeEndIf is called.
1692 headerBlock = builder.getBuildPoint();
1693
1694 function->addBlock(thenBlock);
1695 builder.setBuildPoint(thenBlock);
1696}
1697
1698// Comments in header
1699void Builder::If::makeBeginElse()
1700{
1701 // Close out the "then" by having it jump to the mergeBlock
1702 builder.createBranch(mergeBlock);
1703
1704 // Make the first else block and add it to the function
1705 elseBlock = new Block(builder.getUniqueId(), *function);
1706 function->addBlock(elseBlock);
1707
1708 // Start building the else block
1709 builder.setBuildPoint(elseBlock);
1710}
1711
1712// Comments in header
1713void Builder::If::makeEndIf()
1714{
1715 // jump to the merge block
1716 builder.createBranch(mergeBlock);
1717
1718 // Go back to the headerBlock and make the flow control split
1719 builder.setBuildPoint(headerBlock);
John Kessenich55e7d112015-11-15 21:33:39 -07001720 builder.createSelectionMerge(mergeBlock, SelectionControlMaskNone);
John Kessenich140f3df2015-06-26 16:58:36 -06001721 if (elseBlock)
1722 builder.createConditionalBranch(condition, thenBlock, elseBlock);
1723 else
1724 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
1725
1726 // add the merge block to the function
1727 function->addBlock(mergeBlock);
1728 builder.setBuildPoint(mergeBlock);
1729}
1730
1731// Comments in header
1732void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,
1733 std::vector<Block*>& segmentBlocks)
1734{
1735 Function& function = buildPoint->getParent();
1736
1737 // make all the blocks
1738 for (int s = 0; s < numSegments; ++s)
1739 segmentBlocks.push_back(new Block(getUniqueId(), function));
1740
1741 Block* mergeBlock = new Block(getUniqueId(), function);
1742
1743 // make and insert the switch's selection-merge instruction
John Kessenich55e7d112015-11-15 21:33:39 -07001744 createSelectionMerge(mergeBlock, SelectionControlMaskNone);
John Kessenich140f3df2015-06-26 16:58:36 -06001745
1746 // make the switch instruction
1747 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
1748 switchInst->addIdOperand(selector);
Dejan Mircevski454796e2016-01-18 16:18:01 -05001749 auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
1750 switchInst->addIdOperand(defaultOrMerge->getId());
1751 defaultOrMerge->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06001752 for (int i = 0; i < (int)caseValues.size(); ++i) {
1753 switchInst->addImmediateOperand(caseValues[i]);
1754 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
Dejan Mircevski454796e2016-01-18 16:18:01 -05001755 segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06001756 }
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001757 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
John Kessenich140f3df2015-06-26 16:58:36 -06001758
1759 // push the merge block
1760 switchMerges.push(mergeBlock);
1761}
1762
1763// Comments in header
1764void Builder::addSwitchBreak()
1765{
1766 // branch to the top of the merge block stack
1767 createBranch(switchMerges.top());
1768 createAndSetNoPredecessorBlock("post-switch-break");
1769}
1770
1771// Comments in header
1772void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
1773{
1774 int lastSegment = nextSegment - 1;
1775 if (lastSegment >= 0) {
1776 // Close out previous segment by jumping, if necessary, to next segment
1777 if (! buildPoint->isTerminated())
1778 createBranch(segmentBlock[nextSegment]);
1779 }
1780 Block* block = segmentBlock[nextSegment];
1781 block->getParent().addBlock(block);
1782 setBuildPoint(block);
1783}
1784
1785// Comments in header
1786void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
1787{
1788 // Close out previous segment by jumping, if necessary, to next segment
1789 if (! buildPoint->isTerminated())
1790 addSwitchBreak();
1791
1792 switchMerges.top()->getParent().addBlock(switchMerges.top());
1793 setBuildPoint(switchMerges.top());
1794
1795 switchMerges.pop();
1796}
1797
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05001798Block& Builder::makeNewBlock()
1799{
1800 Function& function = buildPoint->getParent();
1801 auto block = new Block(getUniqueId(), function);
1802 function.addBlock(block);
1803 return *block;
1804}
1805
Dejan Mircevski7819bee2016-01-11 09:35:22 -05001806Builder::LoopBlocks& Builder::makeNewLoop()
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05001807{
Dejan Mircevski97605c82016-01-20 10:19:25 -05001808 // Older MSVC versions don't allow inlining of blocks below.
1809 LoopBlocks blocks = {makeNewBlock(), makeNewBlock(), makeNewBlock(), makeNewBlock()};
1810 loops.push(blocks);
Dejan Mircevski7819bee2016-01-11 09:35:22 -05001811 return loops.top();
John Kessenich140f3df2015-06-26 16:58:36 -06001812}
1813
1814void Builder::createLoopContinue()
1815{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05001816 createBranch(&loops.top().continue_target);
John Kessenich140f3df2015-06-26 16:58:36 -06001817 // Set up a block for dead code.
1818 createAndSetNoPredecessorBlock("post-loop-continue");
1819}
1820
John Kessenich140f3df2015-06-26 16:58:36 -06001821void Builder::createLoopExit()
1822{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05001823 createBranch(&loops.top().merge);
John Kessenich140f3df2015-06-26 16:58:36 -06001824 // Set up a block for dead code.
1825 createAndSetNoPredecessorBlock("post-loop-break");
1826}
1827
John Kessenich140f3df2015-06-26 16:58:36 -06001828void Builder::closeLoop()
1829{
John Kessenich140f3df2015-06-26 16:58:36 -06001830 loops.pop();
1831}
1832
1833void Builder::clearAccessChain()
1834{
John Kessenichfa668da2015-09-13 14:46:30 -06001835 accessChain.base = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001836 accessChain.indexChain.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06001837 accessChain.instr = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001838 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06001839 accessChain.component = NoResult;
1840 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06001841 accessChain.isRValue = false;
1842}
1843
1844// Comments in header
John Kessenichfa668da2015-09-13 14:46:30 -06001845void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
John Kessenich140f3df2015-06-26 16:58:36 -06001846{
John Kessenichfa668da2015-09-13 14:46:30 -06001847 // swizzles can be stacked in GLSL, but simplified to a single
1848 // one here; the base type doesn't change
1849 if (accessChain.preSwizzleBaseType == NoType)
1850 accessChain.preSwizzleBaseType = preSwizzleBaseType;
1851
John Kessenich140f3df2015-06-26 16:58:36 -06001852 // if needed, propagate the swizzle for the current access chain
1853 if (accessChain.swizzle.size()) {
1854 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
1855 accessChain.swizzle.resize(0);
1856 for (unsigned int i = 0; i < swizzle.size(); ++i) {
1857 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
1858 }
1859 } else
1860 accessChain.swizzle = swizzle;
1861
1862 // determine if we need to track this swizzle anymore
1863 simplifyAccessChainSwizzle();
1864}
1865
1866// Comments in header
1867void Builder::accessChainStore(Id rvalue)
1868{
1869 assert(accessChain.isRValue == false);
1870
John Kessenich55e7d112015-11-15 21:33:39 -07001871 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06001872 Id base = collapseAccessChain();
1873
John Kessenichfa668da2015-09-13 14:46:30 -06001874 if (accessChain.swizzle.size() && accessChain.component != NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001875 MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");
1876
John Kessenich55e7d112015-11-15 21:33:39 -07001877 // 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 -06001878 // extract and insert elements to perform writeMask and/or swizzle.
1879 Id source = NoResult;
1880 if (accessChain.swizzle.size()) {
1881 Id tempBaseId = createLoad(base);
1882 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);
1883 }
1884
1885 // dynamic component selection
John Kessenichfa668da2015-09-13 14:46:30 -06001886 if (accessChain.component != NoResult) {
John Kessenich140f3df2015-06-26 16:58:36 -06001887 Id tempBaseId = (source == NoResult) ? createLoad(base) : source;
1888 source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);
1889 }
1890
1891 if (source == NoResult)
1892 source = rvalue;
1893
1894 createStore(source, base);
1895}
1896
1897// Comments in header
John Kessenichfa668da2015-09-13 14:46:30 -06001898Id Builder::accessChainLoad(Id resultType)
John Kessenich140f3df2015-06-26 16:58:36 -06001899{
1900 Id id;
1901
1902 if (accessChain.isRValue) {
John Kessenich55e7d112015-11-15 21:33:39 -07001903 // transfer access chain, but keep it static, so we can stay in registers
1904 transferAccessChainSwizzle(false);
John Kessenich140f3df2015-06-26 16:58:36 -06001905 if (accessChain.indexChain.size() > 0) {
John Kessenichfa668da2015-09-13 14:46:30 -06001906 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
1907
John Kessenich140f3df2015-06-26 16:58:36 -06001908 // if all the accesses are constants, we can use OpCompositeExtract
1909 std::vector<unsigned> indexes;
1910 bool constant = true;
1911 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
1912 if (isConstantScalar(accessChain.indexChain[i]))
1913 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
1914 else {
1915 constant = false;
1916 break;
1917 }
1918 }
1919
1920 if (constant)
John Kessenichfa668da2015-09-13 14:46:30 -06001921 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06001922 else {
1923 // make a new function variable for this r-value
1924 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
1925
1926 // store into it
1927 createStore(accessChain.base, lValue);
1928
1929 // move base to the new variable
1930 accessChain.base = lValue;
1931 accessChain.isRValue = false;
1932
1933 // load through the access chain
1934 id = createLoad(collapseAccessChain());
1935 }
1936 } else
1937 id = accessChain.base;
1938 } else {
John Kessenich55e7d112015-11-15 21:33:39 -07001939 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06001940 // load through the access chain
1941 id = createLoad(collapseAccessChain());
1942 }
1943
1944 // Done, unless there are swizzles to do
John Kessenichfa668da2015-09-13 14:46:30 -06001945 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001946 return id;
1947
John Kessenich140f3df2015-06-26 16:58:36 -06001948 // Do remaining swizzling
1949 // First, static swizzling
1950 if (accessChain.swizzle.size()) {
1951 // static swizzle
John Kessenichfa668da2015-09-13 14:46:30 -06001952 Id swizzledType = getScalarTypeId(getTypeId(id));
John Kessenich140f3df2015-06-26 16:58:36 -06001953 if (accessChain.swizzle.size() > 1)
John Kessenichfa668da2015-09-13 14:46:30 -06001954 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
1955 id = createRvalueSwizzle(swizzledType, id, accessChain.swizzle);
John Kessenich140f3df2015-06-26 16:58:36 -06001956 }
1957
1958 // dynamic single-component selection
John Kessenichfa668da2015-09-13 14:46:30 -06001959 if (accessChain.component != NoResult)
1960 id = createVectorExtractDynamic(id, resultType, accessChain.component);
John Kessenich140f3df2015-06-26 16:58:36 -06001961
1962 return id;
1963}
1964
1965Id Builder::accessChainGetLValue()
1966{
1967 assert(accessChain.isRValue == false);
1968
John Kessenich55e7d112015-11-15 21:33:39 -07001969 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06001970 Id lvalue = collapseAccessChain();
1971
1972 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
1973 // extract and insert elements to perform writeMask and/or swizzle. This does not
1974 // go with getting a direct l-value pointer.
1975 assert(accessChain.swizzle.size() == 0);
John Kessenichfa668da2015-09-13 14:46:30 -06001976 assert(accessChain.component == NoResult);
John Kessenich140f3df2015-06-26 16:58:36 -06001977
1978 return lvalue;
1979}
1980
1981void Builder::dump(std::vector<unsigned int>& out) const
1982{
1983 // Header, before first instructions:
1984 out.push_back(MagicNumber);
1985 out.push_back(Version);
1986 out.push_back(builderNumber);
1987 out.push_back(uniqueId + 1);
1988 out.push_back(0);
1989
John Kessenich55e7d112015-11-15 21:33:39 -07001990 // Capabilities
1991 for (auto cap : capabilities) {
1992 Instruction capInst(0, 0, OpCapability);
1993 capInst.addImmediateOperand(cap);
1994 capInst.dump(out);
1995 }
1996
1997 // TBD: OpExtension ...
1998
1999 dumpInstructions(out, imports);
2000 Instruction memInst(0, 0, OpMemoryModel);
2001 memInst.addImmediateOperand(addressModel);
2002 memInst.addImmediateOperand(memoryModel);
2003 memInst.dump(out);
2004
2005 // Instructions saved up while building:
2006 dumpInstructions(out, entryPoints);
2007 dumpInstructions(out, executionModes);
2008
2009 // Debug instructions
John Kessenich140f3df2015-06-26 16:58:36 -06002010 if (source != SourceLanguageUnknown) {
2011 Instruction sourceInst(0, 0, OpSource);
2012 sourceInst.addImmediateOperand(source);
2013 sourceInst.addImmediateOperand(sourceVersion);
2014 sourceInst.dump(out);
2015 }
2016 for (int e = 0; e < (int)extensions.size(); ++e) {
2017 Instruction extInst(0, 0, OpSourceExtension);
2018 extInst.addStringOperand(extensions[e]);
2019 extInst.dump(out);
2020 }
John Kessenich140f3df2015-06-26 16:58:36 -06002021 dumpInstructions(out, names);
2022 dumpInstructions(out, lines);
John Kessenich55e7d112015-11-15 21:33:39 -07002023
2024 // Annotation instructions
John Kessenich140f3df2015-06-26 16:58:36 -06002025 dumpInstructions(out, decorations);
John Kessenich55e7d112015-11-15 21:33:39 -07002026
John Kessenich140f3df2015-06-26 16:58:36 -06002027 dumpInstructions(out, constantsTypesGlobals);
2028 dumpInstructions(out, externals);
2029
2030 // The functions
2031 module.dump(out);
2032}
2033
2034//
2035// Protected methods.
2036//
2037
John Kessenich55e7d112015-11-15 21:33:39 -07002038// Turn the described access chain in 'accessChain' into an instruction
2039// computing its address. This *cannot* include complex swizzles, which must
2040// be handled after this is called, but it does include swizzles that select
2041// an individual element, as a single address of a scalar type can be
2042// computed by an OpAccessChain instruction.
John Kessenich140f3df2015-06-26 16:58:36 -06002043Id Builder::collapseAccessChain()
2044{
John Kessenich140f3df2015-06-26 16:58:36 -06002045 assert(accessChain.isRValue == false);
2046
2047 if (accessChain.indexChain.size() > 0) {
2048 if (accessChain.instr == 0) {
2049 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
2050 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
2051 }
2052
2053 return accessChain.instr;
2054 } else
2055 return accessChain.base;
John Kessenich55e7d112015-11-15 21:33:39 -07002056
2057 // note that non-trivial swizzling is left pending...
John Kessenich140f3df2015-06-26 16:58:36 -06002058}
2059
John Kessenich55e7d112015-11-15 21:33:39 -07002060// clear out swizzle if it is redundant, that is reselecting the same components
2061// that would be present without the swizzle.
John Kessenich140f3df2015-06-26 16:58:36 -06002062void Builder::simplifyAccessChainSwizzle()
2063{
2064 // If the swizzle has fewer components than the vector, it is subsetting, and must stay
2065 // to preserve that fact.
John Kessenichfa668da2015-09-13 14:46:30 -06002066 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
John Kessenich140f3df2015-06-26 16:58:36 -06002067 return;
2068
2069 // if components are out of order, it is a swizzle
2070 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
2071 if (i != accessChain.swizzle[i])
2072 return;
2073 }
2074
2075 // otherwise, there is no need to track this swizzle
2076 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002077 if (accessChain.component == NoResult)
2078 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002079}
2080
John Kessenich55e7d112015-11-15 21:33:39 -07002081// To the extent any swizzling can become part of the chain
2082// of accesses instead of a post operation, make it so.
2083// If 'dynamic' is true, include transfering a non-static component index,
2084// otherwise, only transfer static indexes.
2085//
2086// Also, Boolean vectors are likely to be special. While
2087// for external storage, they should only be integer types,
2088// function-local bool vectors could use sub-word indexing,
2089// so keep that as a separate Insert/Extract on a loaded vector.
2090void Builder::transferAccessChainSwizzle(bool dynamic)
John Kessenich140f3df2015-06-26 16:58:36 -06002091{
John Kessenich55e7d112015-11-15 21:33:39 -07002092 // too complex?
2093 if (accessChain.swizzle.size() > 1)
John Kessenich140f3df2015-06-26 16:58:36 -06002094 return;
2095
John Kessenich55e7d112015-11-15 21:33:39 -07002096 // non existent?
2097 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002098 return;
2099
John Kessenich55e7d112015-11-15 21:33:39 -07002100 // single component...
2101
2102 // skip doing it for Boolean vectors
2103 if (isBoolType(getContainedTypeId(accessChain.preSwizzleBaseType)))
2104 return;
2105
2106 if (accessChain.swizzle.size() == 1) {
2107 // handle static component
John Kessenich140f3df2015-06-26 16:58:36 -06002108 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
John Kessenich55e7d112015-11-15 21:33:39 -07002109 accessChain.swizzle.clear();
2110 // note, the only valid remaining dynamic access would be to this one
2111 // component, so don't bother even looking at accessChain.component
2112 accessChain.preSwizzleBaseType = NoType;
2113 accessChain.component = NoResult;
2114 } else if (dynamic && accessChain.component != NoResult) {
2115 // handle dynamic component
John Kessenich140f3df2015-06-26 16:58:36 -06002116 accessChain.indexChain.push_back(accessChain.component);
John Kessenich55e7d112015-11-15 21:33:39 -07002117 accessChain.preSwizzleBaseType = NoType;
2118 accessChain.component = NoResult;
2119 }
John Kessenich140f3df2015-06-26 16:58:36 -06002120}
2121
2122// Utility method for creating a new block and setting the insert point to
2123// be in it. This is useful for flow-control operations that need a "dummy"
2124// block proceeding them (e.g. instructions after a discard, etc).
2125void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
2126{
2127 Block* block = new Block(getUniqueId(), buildPoint->getParent());
2128 block->setUnreachable();
2129 buildPoint->getParent().addBlock(block);
2130 setBuildPoint(block);
2131
2132 //if (name)
2133 // addName(block->getId(), name);
2134}
2135
2136// Comments in header
2137void Builder::createBranch(Block* block)
2138{
2139 Instruction* branch = new Instruction(OpBranch);
2140 branch->addIdOperand(block->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002141 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002142 block->addPredecessor(buildPoint);
2143}
2144
John Kessenich55e7d112015-11-15 21:33:39 -07002145void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
John Kessenich140f3df2015-06-26 16:58:36 -06002146{
John Kessenich55e7d112015-11-15 21:33:39 -07002147 Instruction* merge = new Instruction(OpSelectionMerge);
John Kessenich140f3df2015-06-26 16:58:36 -06002148 merge->addIdOperand(mergeBlock->getId());
2149 merge->addImmediateOperand(control);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002150 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich140f3df2015-06-26 16:58:36 -06002151}
2152
John Kessenich55e7d112015-11-15 21:33:39 -07002153void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control)
2154{
2155 Instruction* merge = new Instruction(OpLoopMerge);
2156 merge->addIdOperand(mergeBlock->getId());
2157 merge->addIdOperand(continueBlock->getId());
2158 merge->addImmediateOperand(control);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002159 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich55e7d112015-11-15 21:33:39 -07002160}
2161
John Kessenich140f3df2015-06-26 16:58:36 -06002162void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
2163{
2164 Instruction* branch = new Instruction(OpBranchConditional);
2165 branch->addIdOperand(condition);
2166 branch->addIdOperand(thenBlock->getId());
2167 branch->addIdOperand(elseBlock->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002168 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002169 thenBlock->addPredecessor(buildPoint);
2170 elseBlock->addPredecessor(buildPoint);
2171}
2172
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002173void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
John Kessenich140f3df2015-06-26 16:58:36 -06002174{
2175 for (int i = 0; i < (int)instructions.size(); ++i) {
2176 instructions[i]->dump(out);
2177 }
2178}
2179
John Kessenich426394d2015-07-23 10:22:48 -06002180void TbdFunctionality(const char* tbd)
2181{
2182 static std::unordered_set<const char*> issued;
2183
2184 if (issued.find(tbd) == issued.end()) {
2185 printf("TBD functionality: %s\n", tbd);
2186 issued.insert(tbd);
2187 }
2188}
2189
John Kessenich140f3df2015-06-26 16:58:36 -06002190void MissingFunctionality(const char* fun)
2191{
2192 printf("Missing functionality: %s\n", fun);
John Kessenich140f3df2015-06-26 16:58:36 -06002193}
2194
John Kessenich140f3df2015-06-26 16:58:36 -06002195}; // end spv namespace