blob: 1411d16335bc3ccac3bf83fa638d8ae858b2e137 [file] [log] [blame]
John Kessenich140f3df2015-06-26 16:58:36 -06001//
John Kessenich6c292d32016-02-15 20:58:50 -07002//Copyright (C) 2014-2015 LunarG, Inc.
3//Copyright (C) 2015-2016 Google, Inc.
John Kessenich140f3df2015-06-26 16:58:36 -06004//
5//All rights reserved.
6//
7//Redistribution and use in source and binary forms, with or without
8//modification, are permitted provided that the following conditions
9//are met:
10//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
23//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34//POSSIBILITY OF SUCH DAMAGE.
35
36//
John Kessenich140f3df2015-06-26 16:58:36 -060037// Helper for making SPIR-V IR. Generally, this is documented in the header
38// SpvBuilder.h.
39//
40
41#include <assert.h>
John Kessenich140f3df2015-06-26 16:58:36 -060042#include <stdlib.h>
43
John Kessenich426394d2015-07-23 10:22:48 -060044#include <unordered_set>
qining1f2820a2016-04-14 18:34:27 -040045#include <algorithm>
John Kessenich426394d2015-07-23 10:22:48 -060046
John Kessenich140f3df2015-06-26 16:58:36 -060047#include "SpvBuilder.h"
48
49#ifndef _WIN32
50 #include <cstdio>
51#endif
52
53namespace spv {
54
Lei Zhang17535f72016-05-04 15:55:59 -040055Builder::Builder(unsigned int magicNumber, SpvBuildLogger* buildLogger) :
John Kessenich140f3df2015-06-26 16:58:36 -060056 source(SourceLanguageUnknown),
57 sourceVersion(0),
58 addressModel(AddressingModelLogical),
59 memoryModel(MemoryModelGLSL450),
John Kessenich55e7d112015-11-15 21:33:39 -070060 builderNumber(magicNumber),
John Kessenich140f3df2015-06-26 16:58:36 -060061 buildPoint(0),
62 uniqueId(0),
qining13545202016-03-21 09:51:37 -040063 mainFunction(0),
Lei Zhang09caf122016-05-02 18:11:54 -040064 generatingOpCodeForSpecConst(false),
Lei Zhang17535f72016-05-04 15:55:59 -040065 logger(buildLogger)
John Kessenich140f3df2015-06-26 16:58:36 -060066{
67 clearAccessChain();
68}
69
70Builder::~Builder()
71{
72}
73
74Id Builder::import(const char* name)
75{
76 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
77 import->addStringOperand(name);
78
Andrew Woloszynb7946d12016-01-18 09:23:56 -050079 imports.push_back(std::unique_ptr<Instruction>(import));
John Kessenich140f3df2015-06-26 16:58:36 -060080 return import->getResultId();
81}
82
83// For creating new groupedTypes (will return old type if the requested one was already made).
84Id Builder::makeVoidType()
85{
86 Instruction* type;
87 if (groupedTypes[OpTypeVoid].size() == 0) {
88 type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
89 groupedTypes[OpTypeVoid].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -050090 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -060091 module.mapInstruction(type);
92 } else
93 type = groupedTypes[OpTypeVoid].back();
94
95 return type->getResultId();
96}
97
98Id Builder::makeBoolType()
99{
100 Instruction* type;
101 if (groupedTypes[OpTypeBool].size() == 0) {
102 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
103 groupedTypes[OpTypeBool].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500104 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600105 module.mapInstruction(type);
106 } else
107 type = groupedTypes[OpTypeBool].back();
108
109 return type->getResultId();
110}
111
John Kessenich55e7d112015-11-15 21:33:39 -0700112Id Builder::makeSamplerType()
113{
114 Instruction* type;
115 if (groupedTypes[OpTypeSampler].size() == 0) {
116 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
117 groupedTypes[OpTypeSampler].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500118 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich55e7d112015-11-15 21:33:39 -0700119 module.mapInstruction(type);
120 } else
121 type = groupedTypes[OpTypeSampler].back();
122
123 return type->getResultId();
124}
125
John Kessenich140f3df2015-06-26 16:58:36 -0600126Id Builder::makePointer(StorageClass storageClass, Id pointee)
127{
128 // try to find it
129 Instruction* type;
130 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
131 type = groupedTypes[OpTypePointer][t];
132 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
133 type->getIdOperand(1) == pointee)
134 return type->getResultId();
135 }
136
137 // not found, make it
138 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
139 type->addImmediateOperand(storageClass);
140 type->addIdOperand(pointee);
141 groupedTypes[OpTypePointer].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500142 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600143 module.mapInstruction(type);
144
145 return type->getResultId();
146}
147
148Id Builder::makeIntegerType(int width, bool hasSign)
149{
150 // try to find it
151 Instruction* type;
152 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
153 type = groupedTypes[OpTypeInt][t];
154 if (type->getImmediateOperand(0) == (unsigned)width &&
155 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
156 return type->getResultId();
157 }
158
159 // not found, make it
160 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
161 type->addImmediateOperand(width);
162 type->addImmediateOperand(hasSign ? 1 : 0);
163 groupedTypes[OpTypeInt].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500164 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600165 module.mapInstruction(type);
166
John Kessenich3c522072016-02-14 17:11:15 -0700167 // deal with capabilities
168 switch (width) {
169 case 16:
170 addCapability(CapabilityInt16);
171 break;
172 case 64:
173 addCapability(CapabilityInt64);
174 break;
175 default:
176 break;
177 }
178
John Kessenich140f3df2015-06-26 16:58:36 -0600179 return type->getResultId();
180}
181
182Id Builder::makeFloatType(int width)
183{
184 // try to find it
185 Instruction* type;
186 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
187 type = groupedTypes[OpTypeFloat][t];
188 if (type->getImmediateOperand(0) == (unsigned)width)
189 return type->getResultId();
190 }
191
192 // not found, make it
193 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
194 type->addImmediateOperand(width);
195 groupedTypes[OpTypeFloat].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500196 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600197 module.mapInstruction(type);
198
John Kessenich3c522072016-02-14 17:11:15 -0700199 // deal with capabilities
200 switch (width) {
201 case 16:
202 addCapability(CapabilityFloat16);
203 break;
204 case 64:
205 addCapability(CapabilityFloat64);
206 break;
207 default:
208 break;
209 }
210
John Kessenich140f3df2015-06-26 16:58:36 -0600211 return type->getResultId();
212}
213
John Kessenich55e7d112015-11-15 21:33:39 -0700214// Make a struct without checking for duplication.
215// See makeStructResultType() for non-decorated structs
216// needed as the result of some instructions, which does
217// check for duplicates.
John Kessenich32cfd492016-02-02 12:37:46 -0700218Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600219{
John Kessenich55e7d112015-11-15 21:33:39 -0700220 // Don't look for previous one, because in the general case,
221 // structs can be duplicated except for decorations.
222
John Kessenich140f3df2015-06-26 16:58:36 -0600223 // not found, make it
224 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
225 for (int op = 0; op < (int)members.size(); ++op)
226 type->addIdOperand(members[op]);
227 groupedTypes[OpTypeStruct].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500228 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600229 module.mapInstruction(type);
230 addName(type->getResultId(), name);
231
232 return type->getResultId();
233}
234
John Kessenich55e7d112015-11-15 21:33:39 -0700235// Make a struct for the simple results of several instructions,
236// checking for duplication.
237Id Builder::makeStructResultType(Id type0, Id type1)
238{
239 // try to find it
240 Instruction* type;
241 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
242 type = groupedTypes[OpTypeStruct][t];
243 if (type->getNumOperands() != 2)
244 continue;
245 if (type->getIdOperand(0) != type0 ||
246 type->getIdOperand(1) != type1)
247 continue;
248 return type->getResultId();
249 }
250
251 // not found, make it
252 std::vector<spv::Id> members;
253 members.push_back(type0);
254 members.push_back(type1);
255
256 return makeStructType(members, "ResType");
257}
258
John Kessenich140f3df2015-06-26 16:58:36 -0600259Id Builder::makeVectorType(Id component, int size)
260{
261 // try to find it
262 Instruction* type;
263 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
264 type = groupedTypes[OpTypeVector][t];
265 if (type->getIdOperand(0) == component &&
266 type->getImmediateOperand(1) == (unsigned)size)
267 return type->getResultId();
268 }
269
270 // not found, make it
271 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
272 type->addIdOperand(component);
273 type->addImmediateOperand(size);
274 groupedTypes[OpTypeVector].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500275 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600276 module.mapInstruction(type);
277
278 return type->getResultId();
279}
280
281Id Builder::makeMatrixType(Id component, int cols, int rows)
282{
283 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
284
285 Id column = makeVectorType(component, rows);
286
287 // try to find it
288 Instruction* type;
289 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
290 type = groupedTypes[OpTypeMatrix][t];
291 if (type->getIdOperand(0) == column &&
292 type->getImmediateOperand(1) == (unsigned)cols)
293 return type->getResultId();
294 }
295
296 // not found, make it
297 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
298 type->addIdOperand(column);
299 type->addImmediateOperand(cols);
300 groupedTypes[OpTypeMatrix].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500301 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600302 module.mapInstruction(type);
303
304 return type->getResultId();
305}
306
John Kessenichc9e0a422015-12-29 21:27:24 -0700307// TODO: performance: track arrays per stride
308// If a stride is supplied (non-zero) make an array.
309// If no stride (0), reuse previous array types.
John Kessenich6c292d32016-02-15 20:58:50 -0700310// 'size' is an Id of a constant or specialization constant of the array size
311Id Builder::makeArrayType(Id element, Id sizeId, int stride)
John Kessenich140f3df2015-06-26 16:58:36 -0600312{
John Kessenich140f3df2015-06-26 16:58:36 -0600313 Instruction* type;
John Kessenichc9e0a422015-12-29 21:27:24 -0700314 if (stride == 0) {
315 // try to find existing type
316 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
317 type = groupedTypes[OpTypeArray][t];
318 if (type->getIdOperand(0) == element &&
319 type->getIdOperand(1) == sizeId)
320 return type->getResultId();
321 }
John Kessenich140f3df2015-06-26 16:58:36 -0600322 }
323
324 // not found, make it
325 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
326 type->addIdOperand(element);
327 type->addIdOperand(sizeId);
328 groupedTypes[OpTypeArray].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500329 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600330 module.mapInstruction(type);
331
332 return type->getResultId();
333}
334
John Kessenichc9a80832015-09-12 12:17:44 -0600335Id Builder::makeRuntimeArray(Id element)
336{
337 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
338 type->addIdOperand(element);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500339 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenichc9a80832015-09-12 12:17:44 -0600340 module.mapInstruction(type);
341
342 return type->getResultId();
343}
344
John Kessenich32cfd492016-02-02 12:37:46 -0700345Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
John Kessenich140f3df2015-06-26 16:58:36 -0600346{
347 // try to find it
348 Instruction* type;
349 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
350 type = groupedTypes[OpTypeFunction][t];
351 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
352 continue;
353 bool mismatch = false;
354 for (int p = 0; p < (int)paramTypes.size(); ++p) {
355 if (paramTypes[p] != type->getIdOperand(p + 1)) {
356 mismatch = true;
357 break;
358 }
359 }
360 if (! mismatch)
John Kessenichc9a80832015-09-12 12:17:44 -0600361 return type->getResultId();
John Kessenich140f3df2015-06-26 16:58:36 -0600362 }
363
364 // not found, make it
365 type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
366 type->addIdOperand(returnType);
367 for (int p = 0; p < (int)paramTypes.size(); ++p)
368 type->addIdOperand(paramTypes[p]);
369 groupedTypes[OpTypeFunction].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500370 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600371 module.mapInstruction(type);
372
373 return type->getResultId();
374}
375
John Kessenich5e4b1242015-08-06 22:53:06 -0600376Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
John Kessenich140f3df2015-06-26 16:58:36 -0600377{
378 // try to find it
379 Instruction* type;
John Kessenich5e4b1242015-08-06 22:53:06 -0600380 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
381 type = groupedTypes[OpTypeImage][t];
John Kessenich140f3df2015-06-26 16:58:36 -0600382 if (type->getIdOperand(0) == sampledType &&
383 type->getImmediateOperand(1) == (unsigned int)dim &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600384 type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
John Kessenich140f3df2015-06-26 16:58:36 -0600385 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600386 type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
387 type->getImmediateOperand(5) == sampled &&
388 type->getImmediateOperand(6) == (unsigned int)format)
John Kessenich140f3df2015-06-26 16:58:36 -0600389 return type->getResultId();
390 }
391
392 // not found, make it
John Kessenich5e4b1242015-08-06 22:53:06 -0600393 type = new Instruction(getUniqueId(), NoType, OpTypeImage);
John Kessenich140f3df2015-06-26 16:58:36 -0600394 type->addIdOperand(sampledType);
395 type->addImmediateOperand( dim);
John Kessenich5e4b1242015-08-06 22:53:06 -0600396 type->addImmediateOperand( depth ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600397 type->addImmediateOperand(arrayed ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600398 type->addImmediateOperand( ms ? 1 : 0);
John Kessenich5e4b1242015-08-06 22:53:06 -0600399 type->addImmediateOperand(sampled);
400 type->addImmediateOperand((unsigned int)format);
John Kessenich140f3df2015-06-26 16:58:36 -0600401
John Kessenich5e4b1242015-08-06 22:53:06 -0600402 groupedTypes[OpTypeImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500403 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich5e4b1242015-08-06 22:53:06 -0600404 module.mapInstruction(type);
405
John Kessenichb0364dc2016-02-14 17:37:30 -0700406 // deal with capabilities
407 switch (dim) {
408 case DimBuffer:
409 if (sampled)
410 addCapability(CapabilitySampledBuffer);
411 else
412 addCapability(CapabilityImageBuffer);
413 break;
414 case Dim1D:
415 if (sampled)
416 addCapability(CapabilitySampled1D);
417 else
418 addCapability(CapabilityImage1D);
419 break;
420 case DimCube:
421 if (arrayed) {
422 if (sampled)
423 addCapability(CapabilitySampledCubeArray);
424 else
425 addCapability(CapabilityImageCubeArray);
426 }
427 break;
428 case DimRect:
429 if (sampled)
430 addCapability(CapabilitySampledRect);
431 else
432 addCapability(CapabilityImageRect);
433 break;
434 case DimSubpassData:
435 addCapability(CapabilityInputAttachment);
436 break;
437 default:
438 break;
439 }
440
441 if (ms) {
442 if (arrayed)
443 addCapability(CapabilityImageMSArray);
444 if (! sampled)
445 addCapability(CapabilityStorageImageMultisample);
446 }
447
John Kessenich5e4b1242015-08-06 22:53:06 -0600448 return type->getResultId();
449}
450
451Id Builder::makeSampledImageType(Id imageType)
452{
453 // try to find it
454 Instruction* type;
455 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
456 type = groupedTypes[OpTypeSampledImage][t];
457 if (type->getIdOperand(0) == imageType)
458 return type->getResultId();
459 }
460
461 // not found, make it
462 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
463 type->addIdOperand(imageType);
464
465 groupedTypes[OpTypeSampledImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500466 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600467 module.mapInstruction(type);
468
469 return type->getResultId();
470}
471
472Id Builder::getDerefTypeId(Id resultId) const
473{
474 Id typeId = getTypeId(resultId);
475 assert(isPointerType(typeId));
476
477 return module.getInstruction(typeId)->getImmediateOperand(1);
478}
479
480Op Builder::getMostBasicTypeClass(Id typeId) const
481{
482 Instruction* instr = module.getInstruction(typeId);
483
484 Op typeClass = instr->getOpCode();
485 switch (typeClass)
486 {
487 case OpTypeVoid:
488 case OpTypeBool:
489 case OpTypeInt:
490 case OpTypeFloat:
491 case OpTypeStruct:
492 return typeClass;
493 case OpTypeVector:
494 case OpTypeMatrix:
495 case OpTypeArray:
496 case OpTypeRuntimeArray:
497 return getMostBasicTypeClass(instr->getIdOperand(0));
498 case OpTypePointer:
499 return getMostBasicTypeClass(instr->getIdOperand(1));
500 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700501 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600502 return OpTypeFloat;
503 }
504}
505
John Kessenich22118352015-12-21 20:54:09 -0700506int Builder::getNumTypeConstituents(Id typeId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600507{
508 Instruction* instr = module.getInstruction(typeId);
509
510 switch (instr->getOpCode())
511 {
512 case OpTypeBool:
513 case OpTypeInt:
514 case OpTypeFloat:
515 return 1;
516 case OpTypeVector:
517 case OpTypeMatrix:
518 return instr->getImmediateOperand(1);
John Kessenich6c292d32016-02-15 20:58:50 -0700519 case OpTypeArray:
520 {
521 Id lengthId = instr->getImmediateOperand(1);
522 return module.getInstruction(lengthId)->getImmediateOperand(0);
523 }
John Kessenich22118352015-12-21 20:54:09 -0700524 case OpTypeStruct:
525 return instr->getNumOperands();
John Kessenich140f3df2015-06-26 16:58:36 -0600526 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700527 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600528 return 1;
529 }
530}
531
532// Return the lowest-level type of scalar that an homogeneous composite is made out of.
533// Typically, this is just to find out if something is made out of ints or floats.
534// However, it includes returning a structure, if say, it is an array of structure.
535Id Builder::getScalarTypeId(Id typeId) const
536{
537 Instruction* instr = module.getInstruction(typeId);
538
539 Op typeClass = instr->getOpCode();
540 switch (typeClass)
541 {
542 case OpTypeVoid:
543 case OpTypeBool:
544 case OpTypeInt:
545 case OpTypeFloat:
546 case OpTypeStruct:
547 return instr->getResultId();
548 case OpTypeVector:
549 case OpTypeMatrix:
550 case OpTypeArray:
551 case OpTypeRuntimeArray:
552 case OpTypePointer:
553 return getScalarTypeId(getContainedTypeId(typeId));
554 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700555 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600556 return NoResult;
557 }
558}
559
560// Return the type of 'member' of a composite.
561Id Builder::getContainedTypeId(Id typeId, int member) const
562{
563 Instruction* instr = module.getInstruction(typeId);
564
565 Op typeClass = instr->getOpCode();
566 switch (typeClass)
567 {
568 case OpTypeVector:
569 case OpTypeMatrix:
570 case OpTypeArray:
571 case OpTypeRuntimeArray:
572 return instr->getIdOperand(0);
573 case OpTypePointer:
574 return instr->getIdOperand(1);
575 case OpTypeStruct:
576 return instr->getIdOperand(member);
577 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700578 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600579 return NoResult;
580 }
581}
582
583// Return the immediately contained type of a given composite type.
584Id Builder::getContainedTypeId(Id typeId) const
585{
586 return getContainedTypeId(typeId, 0);
587}
588
589// See if a scalar constant of this type has already been created, so it
590// can be reused rather than duplicated. (Required by the specification).
John Kessenich55e7d112015-11-15 21:33:39 -0700591Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const
John Kessenich140f3df2015-06-26 16:58:36 -0600592{
593 Instruction* constant;
594 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
595 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700596 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600597 constant->getTypeId() == typeId &&
598 constant->getImmediateOperand(0) == value)
599 return constant->getResultId();
600 }
601
602 return 0;
603}
604
Rex Xu8ff43de2016-04-22 16:51:45 +0800605// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
John Kessenich55e7d112015-11-15 21:33:39 -0700606Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const
John Kessenich140f3df2015-06-26 16:58:36 -0600607{
608 Instruction* constant;
609 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
610 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700611 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600612 constant->getTypeId() == typeId &&
613 constant->getImmediateOperand(0) == v1 &&
614 constant->getImmediateOperand(1) == v2)
615 return constant->getResultId();
616 }
617
618 return 0;
619}
620
John Kessenichf685df82015-10-13 10:55:08 -0600621// Return true if consuming 'opcode' means consuming a constant.
622// "constant" here means after final transform to executable code,
623// the value consumed will be a constant, so includes specialization.
John Kessenich71631272015-10-13 10:39:19 -0600624bool Builder::isConstantOpCode(Op opcode) const
625{
626 switch (opcode) {
627 case OpUndef:
628 case OpConstantTrue:
629 case OpConstantFalse:
630 case OpConstant:
631 case OpConstantComposite:
632 case OpConstantSampler:
633 case OpConstantNull:
634 case OpSpecConstantTrue:
635 case OpSpecConstantFalse:
636 case OpSpecConstant:
637 case OpSpecConstantComposite:
638 case OpSpecConstantOp:
639 return true;
640 default:
641 return false;
642 }
643}
644
qining27e04a02016-04-14 16:40:20 -0400645// Return true if consuming 'opcode' means consuming a specialization constant.
646bool Builder::isSpecConstantOpCode(Op opcode) const
647{
648 switch (opcode) {
649 case OpSpecConstantTrue:
650 case OpSpecConstantFalse:
651 case OpSpecConstant:
652 case OpSpecConstantComposite:
653 case OpSpecConstantOp:
654 return true;
655 default:
656 return false;
657 }
658}
659
John Kessenich55e7d112015-11-15 21:33:39 -0700660Id Builder::makeBoolConstant(bool b, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600661{
662 Id typeId = makeBoolType();
663 Instruction* constant;
John Kessenich55e7d112015-11-15 21:33:39 -0700664 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
John Kessenich140f3df2015-06-26 16:58:36 -0600665
John Kessenich6c292d32016-02-15 20:58:50 -0700666 // See if we already made it. Applies only to regular constants, because specialization constants
667 // must remain distinct for the purpose of applying a SpecId decoration.
668 if (! specConstant) {
669 Id existing = 0;
670 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
671 constant = groupedConstants[OpTypeBool][i];
672 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
673 existing = constant->getResultId();
674 }
John Kessenich140f3df2015-06-26 16:58:36 -0600675
John Kessenich6c292d32016-02-15 20:58:50 -0700676 if (existing)
677 return existing;
678 }
John Kessenich140f3df2015-06-26 16:58:36 -0600679
680 // Make it
John Kessenich55e7d112015-11-15 21:33:39 -0700681 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500682 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600683 groupedConstants[OpTypeBool].push_back(c);
684 module.mapInstruction(c);
685
686 return c->getResultId();
687}
688
John Kessenich55e7d112015-11-15 21:33:39 -0700689Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600690{
John Kessenich55e7d112015-11-15 21:33:39 -0700691 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich6c292d32016-02-15 20:58:50 -0700692
693 // See if we already made it. Applies only to regular constants, because specialization constants
694 // must remain distinct for the purpose of applying a SpecId decoration.
695 if (! specConstant) {
696 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
697 if (existing)
698 return existing;
699 }
John Kessenich140f3df2015-06-26 16:58:36 -0600700
John Kessenich55e7d112015-11-15 21:33:39 -0700701 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600702 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500703 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600704 groupedConstants[OpTypeInt].push_back(c);
705 module.mapInstruction(c);
706
707 return c->getResultId();
708}
709
Rex Xu8ff43de2016-04-22 16:51:45 +0800710Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
711{
712 Op opcode = specConstant ? OpSpecConstant : OpConstant;
713
714 unsigned op1 = value & 0xFFFFFFFF;
715 unsigned op2 = value >> 32;
716
717 // See if we already made it. Applies only to regular constants, because specialization constants
718 // must remain distinct for the purpose of applying a SpecId decoration.
719 if (! specConstant) {
720 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
721 if (existing)
722 return existing;
723 }
724
725 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
726 c->addImmediateOperand(op1);
727 c->addImmediateOperand(op2);
728 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
729 groupedConstants[OpTypeInt].push_back(c);
730 module.mapInstruction(c);
731
732 return c->getResultId();
733}
734
John Kessenich55e7d112015-11-15 21:33:39 -0700735Id Builder::makeFloatConstant(float f, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600736{
John Kessenich55e7d112015-11-15 21:33:39 -0700737 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600738 Id typeId = makeFloatType(32);
Mark Adams18b637f2016-02-23 12:17:11 -0500739 union { float fl; unsigned int ui; } u;
740 u.fl = f;
741 unsigned value = u.ui;
John Kessenich6c292d32016-02-15 20:58:50 -0700742
743 // See if we already made it. Applies only to regular constants, because specialization constants
744 // must remain distinct for the purpose of applying a SpecId decoration.
745 if (! specConstant) {
746 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
747 if (existing)
748 return existing;
749 }
John Kessenich140f3df2015-06-26 16:58:36 -0600750
John Kessenich55e7d112015-11-15 21:33:39 -0700751 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600752 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500753 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600754 groupedConstants[OpTypeFloat].push_back(c);
755 module.mapInstruction(c);
756
757 return c->getResultId();
758}
759
John Kessenich55e7d112015-11-15 21:33:39 -0700760Id Builder::makeDoubleConstant(double d, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600761{
John Kessenich55e7d112015-11-15 21:33:39 -0700762 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600763 Id typeId = makeFloatType(64);
Mark Adams18b637f2016-02-23 12:17:11 -0500764 union { double db; unsigned long long ull; } u;
765 u.db = d;
766 unsigned long long value = u.ull;
John Kessenich140f3df2015-06-26 16:58:36 -0600767 unsigned op1 = value & 0xFFFFFFFF;
768 unsigned op2 = value >> 32;
John Kessenich6c292d32016-02-15 20:58:50 -0700769
770 // See if we already made it. Applies only to regular constants, because specialization constants
771 // must remain distinct for the purpose of applying a SpecId decoration.
772 if (! specConstant) {
773 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
774 if (existing)
775 return existing;
776 }
John Kessenich140f3df2015-06-26 16:58:36 -0600777
John Kessenich55e7d112015-11-15 21:33:39 -0700778 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600779 c->addImmediateOperand(op1);
780 c->addImmediateOperand(op2);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500781 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600782 groupedConstants[OpTypeFloat].push_back(c);
783 module.mapInstruction(c);
784
785 return c->getResultId();
786}
787
788Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
789{
790 Instruction* constant = 0;
791 bool found = false;
792 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
793 constant = groupedConstants[typeClass][i];
794
795 // same shape?
796 if (constant->getNumOperands() != (int)comps.size())
797 continue;
798
799 // same contents?
800 bool mismatch = false;
801 for (int op = 0; op < constant->getNumOperands(); ++op) {
802 if (constant->getIdOperand(op) != comps[op]) {
803 mismatch = true;
804 break;
805 }
806 }
807 if (! mismatch) {
808 found = true;
809 break;
810 }
811 }
812
813 return found ? constant->getResultId() : NoResult;
814}
815
816// Comments in header
John Kessenich6c292d32016-02-15 20:58:50 -0700817Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600818{
John Kessenich6c292d32016-02-15 20:58:50 -0700819 Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
John Kessenich140f3df2015-06-26 16:58:36 -0600820 assert(typeId);
821 Op typeClass = getTypeClass(typeId);
822
823 switch (typeClass) {
824 case OpTypeVector:
825 case OpTypeArray:
826 case OpTypeStruct:
827 case OpTypeMatrix:
828 break;
829 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700830 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600831 return makeFloatConstant(0.0);
832 }
833
John Kessenich6c292d32016-02-15 20:58:50 -0700834 if (! specConstant) {
835 Id existing = findCompositeConstant(typeClass, members);
836 if (existing)
837 return existing;
838 }
John Kessenich140f3df2015-06-26 16:58:36 -0600839
John Kessenich6c292d32016-02-15 20:58:50 -0700840 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600841 for (int op = 0; op < (int)members.size(); ++op)
842 c->addIdOperand(members[op]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500843 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600844 groupedConstants[typeClass].push_back(c);
845 module.mapInstruction(c);
846
847 return c->getResultId();
848}
849
John Kessenich55e7d112015-11-15 21:33:39 -0700850Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600851{
852 Instruction* entryPoint = new Instruction(OpEntryPoint);
853 entryPoint->addImmediateOperand(model);
854 entryPoint->addIdOperand(function->getId());
John Kessenich5e4b1242015-08-06 22:53:06 -0600855 entryPoint->addStringOperand(name);
John Kessenich140f3df2015-06-26 16:58:36 -0600856
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500857 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
John Kessenich55e7d112015-11-15 21:33:39 -0700858
859 return entryPoint;
John Kessenich140f3df2015-06-26 16:58:36 -0600860}
861
John Kessenichb56a26a2015-09-16 16:04:05 -0600862// Currently relying on the fact that all 'value' of interest are small non-negative values.
863void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
John Kessenich140f3df2015-06-26 16:58:36 -0600864{
John Kessenich140f3df2015-06-26 16:58:36 -0600865 Instruction* instr = new Instruction(OpExecutionMode);
866 instr->addIdOperand(entryPoint->getId());
867 instr->addImmediateOperand(mode);
John Kessenichb56a26a2015-09-16 16:04:05 -0600868 if (value1 >= 0)
869 instr->addImmediateOperand(value1);
870 if (value2 >= 0)
871 instr->addImmediateOperand(value2);
872 if (value3 >= 0)
873 instr->addImmediateOperand(value3);
John Kessenich140f3df2015-06-26 16:58:36 -0600874
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500875 executionModes.push_back(std::unique_ptr<Instruction>(instr));
John Kessenich140f3df2015-06-26 16:58:36 -0600876}
877
878void Builder::addName(Id id, const char* string)
879{
880 Instruction* name = new Instruction(OpName);
881 name->addIdOperand(id);
882 name->addStringOperand(string);
883
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500884 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -0600885}
886
887void Builder::addMemberName(Id id, int memberNumber, const char* string)
888{
889 Instruction* name = new Instruction(OpMemberName);
890 name->addIdOperand(id);
891 name->addImmediateOperand(memberNumber);
892 name->addStringOperand(string);
893
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500894 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -0600895}
896
897void Builder::addLine(Id target, Id fileName, int lineNum, int column)
898{
899 Instruction* line = new Instruction(OpLine);
900 line->addIdOperand(target);
901 line->addIdOperand(fileName);
902 line->addImmediateOperand(lineNum);
903 line->addImmediateOperand(column);
904
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500905 lines.push_back(std::unique_ptr<Instruction>(line));
John Kessenich140f3df2015-06-26 16:58:36 -0600906}
907
908void Builder::addDecoration(Id id, Decoration decoration, int num)
909{
John Kessenich4016e382016-07-15 11:53:56 -0600910 if (decoration == spv::DecorationMax)
John Kessenich55e7d112015-11-15 21:33:39 -0700911 return;
John Kessenich140f3df2015-06-26 16:58:36 -0600912 Instruction* dec = new Instruction(OpDecorate);
913 dec->addIdOperand(id);
914 dec->addImmediateOperand(decoration);
915 if (num >= 0)
916 dec->addImmediateOperand(num);
917
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500918 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -0600919}
920
921void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
922{
923 Instruction* dec = new Instruction(OpMemberDecorate);
924 dec->addIdOperand(id);
925 dec->addImmediateOperand(member);
926 dec->addImmediateOperand(decoration);
927 if (num >= 0)
928 dec->addImmediateOperand(num);
929
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500930 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -0600931}
932
933// Comments in header
John Kessenich4d65ee32016-03-12 18:17:47 -0700934Function* Builder::makeEntrypoint(const char* entryPoint)
John Kessenich140f3df2015-06-26 16:58:36 -0600935{
936 assert(! mainFunction);
937
938 Block* entry;
939 std::vector<Id> params;
John Kessenich32cfd492016-02-02 12:37:46 -0700940 std::vector<Decoration> precisions;
John Kessenich140f3df2015-06-26 16:58:36 -0600941
John Kessenich4d65ee32016-03-12 18:17:47 -0700942 mainFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, precisions, &entry);
John Kessenich140f3df2015-06-26 16:58:36 -0600943
944 return mainFunction;
945}
946
947// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -0700948Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
949 const std::vector<Id>& paramTypes, const std::vector<Decoration>& precisions, Block **entry)
John Kessenich140f3df2015-06-26 16:58:36 -0600950{
John Kessenich32cfd492016-02-02 12:37:46 -0700951 // Make the function and initial instructions in it
John Kessenich140f3df2015-06-26 16:58:36 -0600952 Id typeId = makeFunctionType(returnType, paramTypes);
baldurkd76692d2015-07-12 11:32:58 +0200953 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
John Kessenich140f3df2015-06-26 16:58:36 -0600954 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
955
John Kessenich32cfd492016-02-02 12:37:46 -0700956 // Set up the precisions
957 setPrecision(function->getId(), precision);
958 for (unsigned p = 0; p < (unsigned)precisions.size(); ++p)
959 setPrecision(firstParamId + p, precisions[p]);
960
961 // CFG
John Kessenich140f3df2015-06-26 16:58:36 -0600962 if (entry) {
963 *entry = new Block(getUniqueId(), *function);
964 function->addBlock(*entry);
965 setBuildPoint(*entry);
966 }
967
968 if (name)
969 addName(function->getId(), name);
970
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500971 functions.push_back(std::unique_ptr<Function>(function));
972
John Kessenich140f3df2015-06-26 16:58:36 -0600973 return function;
974}
975
976// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -0600977void Builder::makeReturn(bool implicit, Id retVal)
John Kessenich140f3df2015-06-26 16:58:36 -0600978{
John Kesseniche770b3e2015-09-14 20:58:02 -0600979 if (retVal) {
John Kessenich140f3df2015-06-26 16:58:36 -0600980 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
981 inst->addIdOperand(retVal);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500982 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -0600983 } else
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500984 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
John Kessenich140f3df2015-06-26 16:58:36 -0600985
986 if (! implicit)
987 createAndSetNoPredecessorBlock("post-return");
988}
989
990// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -0600991void Builder::leaveFunction()
John Kessenich140f3df2015-06-26 16:58:36 -0600992{
993 Block* block = buildPoint;
994 Function& function = buildPoint->getParent();
995 assert(block);
996
997 // If our function did not contain a return, add a return void now.
998 if (! block->isTerminated()) {
Dejan Mircevskied55bcd2016-01-19 21:13:38 -0500999 if (function.getReturnType() == makeVoidType())
1000 makeReturn(true);
1001 else {
1002 makeReturn(true, createUndefined(function.getReturnType()));
John Kessenich140f3df2015-06-26 16:58:36 -06001003 }
1004 }
John Kessenich140f3df2015-06-26 16:58:36 -06001005}
1006
1007// Comments in header
1008void Builder::makeDiscard()
1009{
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001010 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
John Kessenich140f3df2015-06-26 16:58:36 -06001011 createAndSetNoPredecessorBlock("post-discard");
1012}
1013
1014// Comments in header
1015Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
1016{
1017 Id pointerType = makePointer(storageClass, type);
1018 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
1019 inst->addImmediateOperand(storageClass);
1020
1021 switch (storageClass) {
John Kessenich140f3df2015-06-26 16:58:36 -06001022 case StorageClassFunction:
1023 // Validation rules require the declaration in the entry block
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001024 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -06001025 break;
1026
1027 default:
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001028 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
John Kessenich55e7d112015-11-15 21:33:39 -07001029 module.mapInstruction(inst);
John Kessenich140f3df2015-06-26 16:58:36 -06001030 break;
1031 }
1032
1033 if (name)
1034 addName(inst->getResultId(), name);
1035
1036 return inst->getResultId();
1037}
1038
1039// Comments in header
Miro Knejp28f9b1c2015-08-11 02:45:24 +02001040Id Builder::createUndefined(Id type)
1041{
1042 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001043 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
Miro Knejp28f9b1c2015-08-11 02:45:24 +02001044 return inst->getResultId();
1045}
1046
1047// Comments in header
John Kessenich140f3df2015-06-26 16:58:36 -06001048void Builder::createStore(Id rValue, Id lValue)
1049{
1050 Instruction* store = new Instruction(OpStore);
1051 store->addIdOperand(lValue);
1052 store->addIdOperand(rValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001053 buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
John Kessenich140f3df2015-06-26 16:58:36 -06001054}
1055
1056// Comments in header
1057Id Builder::createLoad(Id lValue)
1058{
1059 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
1060 load->addIdOperand(lValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001061 buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
John Kessenich140f3df2015-06-26 16:58:36 -06001062
1063 return load->getResultId();
1064}
1065
1066// Comments in header
1067Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)
1068{
1069 // Figure out the final resulting type.
1070 spv::Id typeId = getTypeId(base);
1071 assert(isPointerType(typeId) && offsets.size() > 0);
1072 typeId = getContainedTypeId(typeId);
1073 for (int i = 0; i < (int)offsets.size(); ++i) {
1074 if (isStructType(typeId)) {
1075 assert(isConstantScalar(offsets[i]));
1076 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
1077 } else
1078 typeId = getContainedTypeId(typeId, offsets[i]);
1079 }
1080 typeId = makePointer(storageClass, typeId);
1081
1082 // Make the instruction
1083 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
1084 chain->addIdOperand(base);
1085 for (int i = 0; i < (int)offsets.size(); ++i)
1086 chain->addIdOperand(offsets[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001087 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
John Kessenich140f3df2015-06-26 16:58:36 -06001088
1089 return chain->getResultId();
1090}
1091
John Kessenichee21fc92015-09-21 21:50:29 -06001092Id Builder::createArrayLength(Id base, unsigned int member)
1093{
1094 Instruction* length = new Instruction(getUniqueId(), makeIntType(32), OpArrayLength);
1095 length->addIdOperand(base);
1096 length->addImmediateOperand(member);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001097 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
John Kessenichee21fc92015-09-21 21:50:29 -06001098
1099 return length->getResultId();
1100}
1101
John Kessenich140f3df2015-06-26 16:58:36 -06001102Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
1103{
qining13545202016-03-21 09:51:37 -04001104 // Generate code for spec constants if in spec constant operation
1105 // generation mode.
1106 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001107 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index));
qining13545202016-03-21 09:51:37 -04001108 }
John Kessenich140f3df2015-06-26 16:58:36 -06001109 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1110 extract->addIdOperand(composite);
1111 extract->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001112 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001113
1114 return extract->getResultId();
1115}
1116
1117Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)
1118{
qining13545202016-03-21 09:51:37 -04001119 // Generate code for spec constants if in spec constant operation
1120 // generation mode.
1121 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001122 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
qining13545202016-03-21 09:51:37 -04001123 }
John Kessenich140f3df2015-06-26 16:58:36 -06001124 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1125 extract->addIdOperand(composite);
1126 for (int i = 0; i < (int)indexes.size(); ++i)
1127 extract->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001128 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001129
1130 return extract->getResultId();
1131}
1132
1133Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
1134{
1135 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1136 insert->addIdOperand(object);
1137 insert->addIdOperand(composite);
1138 insert->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001139 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001140
1141 return insert->getResultId();
1142}
1143
1144Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)
1145{
1146 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1147 insert->addIdOperand(object);
1148 insert->addIdOperand(composite);
1149 for (int i = 0; i < (int)indexes.size(); ++i)
1150 insert->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001151 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001152
1153 return insert->getResultId();
1154}
1155
1156Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
1157{
1158 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
1159 extract->addIdOperand(vector);
1160 extract->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001161 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001162
1163 return extract->getResultId();
1164}
1165
1166Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
1167{
1168 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
1169 insert->addIdOperand(vector);
1170 insert->addIdOperand(component);
1171 insert->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001172 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001173
1174 return insert->getResultId();
1175}
1176
1177// An opcode that has no operands, no result id, and no type
1178void Builder::createNoResultOp(Op opCode)
1179{
1180 Instruction* op = new Instruction(opCode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001181 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001182}
1183
1184// An opcode that has one operand, no result id, and no type
1185void Builder::createNoResultOp(Op opCode, Id operand)
1186{
1187 Instruction* op = new Instruction(opCode);
1188 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001189 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001190}
1191
Rex Xufc618912015-09-09 16:42:49 +08001192// An opcode that has one operand, no result id, and no type
1193void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
1194{
1195 Instruction* op = new Instruction(opCode);
rdb32084e82016-02-23 22:17:38 +01001196 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1197 op->addIdOperand(*it);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001198 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
Rex Xufc618912015-09-09 16:42:49 +08001199}
1200
John Kessenich5e4b1242015-08-06 22:53:06 -06001201void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
John Kessenich140f3df2015-06-26 16:58:36 -06001202{
1203 Instruction* op = new Instruction(OpControlBarrier);
John Kessenich5e4b1242015-08-06 22:53:06 -06001204 op->addImmediateOperand(makeUintConstant(execution));
1205 op->addImmediateOperand(makeUintConstant(memory));
1206 op->addImmediateOperand(makeUintConstant(semantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001207 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001208}
1209
1210void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
1211{
1212 Instruction* op = new Instruction(OpMemoryBarrier);
John Kessenich5e4b1242015-08-06 22:53:06 -06001213 op->addImmediateOperand(makeUintConstant(executionScope));
1214 op->addImmediateOperand(makeUintConstant(memorySemantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001215 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001216}
1217
1218// An opcode that has one operands, a result id, and a type
1219Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
1220{
qining13545202016-03-21 09:51:37 -04001221 // Generate code for spec constants if in spec constant operation
1222 // generation mode.
1223 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001224 return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
qining13545202016-03-21 09:51:37 -04001225 }
John Kessenich140f3df2015-06-26 16:58:36 -06001226 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1227 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001228 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001229
1230 return op->getResultId();
1231}
1232
1233Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
1234{
qining13545202016-03-21 09:51:37 -04001235 // Generate code for spec constants if in spec constant operation
1236 // generation mode.
1237 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001238 std::vector<Id> operands(2);
1239 operands[0] = left; operands[1] = right;
1240 return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
qining13545202016-03-21 09:51:37 -04001241 }
John Kessenich140f3df2015-06-26 16:58:36 -06001242 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1243 op->addIdOperand(left);
1244 op->addIdOperand(right);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001245 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001246
1247 return op->getResultId();
1248}
1249
1250Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
1251{
qininge24aa5e2016-04-07 15:40:27 -04001252 // Generate code for spec constants if in spec constant operation
1253 // generation mode.
1254 if (generatingOpCodeForSpecConst) {
1255 std::vector<Id> operands(3);
qining189b2032016-04-12 23:16:20 -04001256 operands[0] = op1;
1257 operands[1] = op2;
1258 operands[2] = op3;
qininge24aa5e2016-04-07 15:40:27 -04001259 return createSpecConstantOp(
1260 opCode, typeId, operands, std::vector<Id>());
1261 }
John Kessenich140f3df2015-06-26 16:58:36 -06001262 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1263 op->addIdOperand(op1);
1264 op->addIdOperand(op2);
1265 op->addIdOperand(op3);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001266 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001267
1268 return op->getResultId();
1269}
1270
John Kessenich5e4b1242015-08-06 22:53:06 -06001271Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
John Kessenich140f3df2015-06-26 16:58:36 -06001272{
1273 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
rdb32084e82016-02-23 22:17:38 +01001274 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1275 op->addIdOperand(*it);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001276 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001277
1278 return op->getResultId();
1279}
1280
qining5c61d8e2016-03-31 13:57:28 -04001281Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals)
1282{
qining13545202016-03-21 09:51:37 -04001283 Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
1284 op->addImmediateOperand((unsigned) opCode);
1285 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1286 op->addIdOperand(*it);
1287 for (auto it = literals.cbegin(); it != literals.cend(); ++it)
1288 op->addImmediateOperand(*it);
1289 module.mapInstruction(op);
1290 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
1291
1292 return op->getResultId();
1293}
1294
John Kessenich140f3df2015-06-26 16:58:36 -06001295Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)
1296{
1297 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
1298 op->addIdOperand(function->getId());
1299 for (int a = 0; a < (int)args.size(); ++a)
1300 op->addIdOperand(args[a]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001301 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001302
1303 return op->getResultId();
1304}
1305
1306// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001307Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels)
John Kessenich140f3df2015-06-26 16:58:36 -06001308{
1309 if (channels.size() == 1)
John Kessenich32cfd492016-02-02 12:37:46 -07001310 return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001311
qining13545202016-03-21 09:51:37 -04001312 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001313 std::vector<Id> operands(2);
1314 operands[0] = operands[1] = source;
1315 return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
qining13545202016-03-21 09:51:37 -04001316 }
John Kessenich140f3df2015-06-26 16:58:36 -06001317 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1318 assert(isVector(source));
1319 swizzle->addIdOperand(source);
1320 swizzle->addIdOperand(source);
1321 for (int i = 0; i < (int)channels.size(); ++i)
1322 swizzle->addImmediateOperand(channels[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001323 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001324
John Kessenich32cfd492016-02-02 12:37:46 -07001325 return setPrecision(swizzle->getResultId(), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001326}
1327
1328// Comments in header
1329Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)
1330{
John Kessenich30669532015-08-06 22:02:24 -06001331 assert(getNumComponents(source) == (int)channels.size());
John Kessenich140f3df2015-06-26 16:58:36 -06001332 if (channels.size() == 1 && getNumComponents(source) == 1)
1333 return createCompositeInsert(source, target, typeId, channels.front());
1334
1335 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1336 assert(isVector(source));
1337 assert(isVector(target));
1338 swizzle->addIdOperand(target);
1339 swizzle->addIdOperand(source);
1340
1341 // Set up an identity shuffle from the base value to the result value
1342 unsigned int components[4];
1343 int numTargetComponents = getNumComponents(target);
1344 for (int i = 0; i < numTargetComponents; ++i)
1345 components[i] = i;
1346
1347 // Punch in the l-value swizzle
1348 for (int i = 0; i < (int)channels.size(); ++i)
1349 components[channels[i]] = numTargetComponents + i;
1350
1351 // finish the instruction with these components selectors
1352 for (int i = 0; i < numTargetComponents; ++i)
1353 swizzle->addImmediateOperand(components[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001354 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001355
1356 return swizzle->getResultId();
1357}
1358
1359// Comments in header
1360void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
1361{
1362 int direction = getNumComponents(right) - getNumComponents(left);
1363
1364 if (direction > 0)
John Kessenich76f71392015-12-09 19:08:42 -07001365 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
John Kessenich140f3df2015-06-26 16:58:36 -06001366 else if (direction < 0)
John Kessenich76f71392015-12-09 19:08:42 -07001367 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
John Kessenich140f3df2015-06-26 16:58:36 -06001368
1369 return;
1370}
1371
1372// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001373Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
John Kessenich140f3df2015-06-26 16:58:36 -06001374{
1375 assert(getNumComponents(scalar) == 1);
John Kessenich76f71392015-12-09 19:08:42 -07001376 assert(getTypeId(scalar) == getScalarTypeId(vectorType));
John Kessenich140f3df2015-06-26 16:58:36 -06001377
1378 int numComponents = getNumTypeComponents(vectorType);
1379 if (numComponents == 1)
1380 return scalar;
1381
qining13545202016-03-21 09:51:37 -04001382 Instruction* smear = nullptr;
1383 if (generatingOpCodeForSpecConst) {
1384 auto members = std::vector<spv::Id>(numComponents, scalar);
qining1f2820a2016-04-14 18:34:27 -04001385 // Sometime even in spec-constant-op mode, the temporary vector created by
1386 // promoting a scalar might not be a spec constant. This should depend on
1387 // the scalar.
1388 // e.g.:
1389 // const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
1390 // In such cases, the temporary vector created from a_front_end_const_scalar
1391 // is not a spec constant vector, even though the binary operation node is marked
1392 // as 'specConstant' and we are in spec-constant-op mode.
qining27e04a02016-04-14 16:40:20 -04001393 auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
qining13545202016-03-21 09:51:37 -04001394 smear = module.getInstruction(result_id);
1395 } else {
1396 smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
1397 for (int c = 0; c < numComponents; ++c)
1398 smear->addIdOperand(scalar);
1399 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
1400 }
John Kessenich140f3df2015-06-26 16:58:36 -06001401
John Kessenich32cfd492016-02-02 12:37:46 -07001402 return setPrecision(smear->getResultId(), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001403}
1404
1405// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001406Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
John Kessenich140f3df2015-06-26 16:58:36 -06001407{
1408 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
1409 inst->addIdOperand(builtins);
1410 inst->addImmediateOperand(entryPoint);
1411 for (int arg = 0; arg < (int)args.size(); ++arg)
1412 inst->addIdOperand(args[arg]);
1413
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001414 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich32cfd492016-02-02 12:37:46 -07001415
John Kessenich140f3df2015-06-26 16:58:36 -06001416 return inst->getResultId();
1417}
1418
1419// Accept all parameters needed to create a texture instruction.
1420// Create the correct instruction based on the inputs, and make the call.
John Kessenich019f08f2016-02-15 15:40:42 -07001421Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicitLod, const TextureParameters& parameters)
John Kessenich140f3df2015-06-26 16:58:36 -06001422{
John Kessenich5e4b1242015-08-06 22:53:06 -06001423 static const int maxTextureArgs = 10;
John Kessenich140f3df2015-06-26 16:58:36 -06001424 Id texArgs[maxTextureArgs] = {};
1425
1426 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001427 // Set up the fixed arguments
John Kessenich140f3df2015-06-26 16:58:36 -06001428 //
John Kessenich140f3df2015-06-26 16:58:36 -06001429 int numArgs = 0;
John Kessenich019f08f2016-02-15 15:40:42 -07001430 bool explicitLod = false;
John Kessenich140f3df2015-06-26 16:58:36 -06001431 texArgs[numArgs++] = parameters.sampler;
1432 texArgs[numArgs++] = parameters.coords;
John Kessenich76d4dfc2016-06-16 12:43:23 -06001433 if (parameters.Dref != NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001434 texArgs[numArgs++] = parameters.Dref;
John Kessenich76d4dfc2016-06-16 12:43:23 -06001435 if (parameters.component != NoResult)
1436 texArgs[numArgs++] = parameters.component;
John Kessenich140f3df2015-06-26 16:58:36 -06001437
1438 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001439 // Set up the optional arguments
1440 //
1441 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
1442 ++numArgs; // speculatively make room for the mask operand
1443 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
1444 if (parameters.bias) {
1445 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
1446 texArgs[numArgs++] = parameters.bias;
1447 }
1448 if (parameters.lod) {
1449 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1450 texArgs[numArgs++] = parameters.lod;
John Kessenich019f08f2016-02-15 15:40:42 -07001451 explicitLod = true;
1452 } else if (parameters.gradX) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001453 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
1454 texArgs[numArgs++] = parameters.gradX;
1455 texArgs[numArgs++] = parameters.gradY;
John Kessenich019f08f2016-02-15 15:40:42 -07001456 explicitLod = true;
1457 } else if (noImplicitLod && ! fetch && ! gather) {
1458 // have to explicitly use lod of 0 if not allowed to have them be implicit, and
1459 // we would otherwise be about to issue an implicit instruction
1460 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1461 texArgs[numArgs++] = makeFloatConstant(0.0);
1462 explicitLod = true;
John Kessenich5e4b1242015-08-06 22:53:06 -06001463 }
1464 if (parameters.offset) {
Rex Xu86e60812015-10-11 19:37:48 +08001465 if (isConstant(parameters.offset))
1466 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
Rex Xu58390312016-05-11 16:38:50 +08001467 else {
1468 addCapability(CapabilityImageGatherExtended);
Rex Xu86e60812015-10-11 19:37:48 +08001469 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
Rex Xu58390312016-05-11 16:38:50 +08001470 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001471 texArgs[numArgs++] = parameters.offset;
1472 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001473 if (parameters.offsets) {
1474 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
1475 texArgs[numArgs++] = parameters.offsets;
1476 }
1477 if (parameters.sample) {
1478 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
1479 texArgs[numArgs++] = parameters.sample;
1480 }
Rex Xu48edadf2015-12-31 16:11:41 +08001481 if (parameters.lodClamp) {
John Kessenich5e801132016-02-15 11:09:46 -07001482 // capability if this bit is used
1483 addCapability(CapabilityMinLod);
1484
Rex Xu48edadf2015-12-31 16:11:41 +08001485 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
1486 texArgs[numArgs++] = parameters.lodClamp;
1487 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001488 if (mask == ImageOperandsMaskNone)
1489 --numArgs; // undo speculative reservation for the mask argument
1490 else
1491 texArgs[optArgNum] = mask;
1492
1493 //
John Kessenich140f3df2015-06-26 16:58:36 -06001494 // Set up the instruction
1495 //
John Kessenich019f08f2016-02-15 15:40:42 -07001496 Op opCode = OpNop; // All paths below need to set this
Jason Ekstrand18b9fbd2015-09-05 14:14:48 -07001497 if (fetch) {
Rex Xu48edadf2015-12-31 16:11:41 +08001498 if (sparse)
1499 opCode = OpImageSparseFetch;
1500 else
1501 opCode = OpImageFetch;
John Kessenich55e7d112015-11-15 21:33:39 -07001502 } else if (gather) {
1503 if (parameters.Dref)
Rex Xu48edadf2015-12-31 16:11:41 +08001504 if (sparse)
1505 opCode = OpImageSparseDrefGather;
1506 else
1507 opCode = OpImageDrefGather;
John Kessenich55e7d112015-11-15 21:33:39 -07001508 else
Rex Xu48edadf2015-12-31 16:11:41 +08001509 if (sparse)
1510 opCode = OpImageSparseGather;
1511 else
1512 opCode = OpImageGather;
John Kessenich019f08f2016-02-15 15:40:42 -07001513 } else if (explicitLod) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001514 if (parameters.Dref) {
1515 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001516 if (sparse)
1517 opCode = OpImageSparseSampleProjDrefExplicitLod;
1518 else
1519 opCode = OpImageSampleProjDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001520 else
Rex Xu48edadf2015-12-31 16:11:41 +08001521 if (sparse)
1522 opCode = OpImageSparseSampleDrefExplicitLod;
1523 else
1524 opCode = OpImageSampleDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001525 } else {
1526 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001527 if (sparse)
1528 opCode = OpImageSparseSampleProjExplicitLod;
1529 else
1530 opCode = OpImageSampleProjExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001531 else
Rex Xu48edadf2015-12-31 16:11:41 +08001532 if (sparse)
1533 opCode = OpImageSparseSampleExplicitLod;
1534 else
1535 opCode = OpImageSampleExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001536 }
1537 } else {
1538 if (parameters.Dref) {
1539 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001540 if (sparse)
1541 opCode = OpImageSparseSampleProjDrefImplicitLod;
1542 else
1543 opCode = OpImageSampleProjDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001544 else
Rex Xu48edadf2015-12-31 16:11:41 +08001545 if (sparse)
1546 opCode = OpImageSparseSampleDrefImplicitLod;
1547 else
1548 opCode = OpImageSampleDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001549 } else {
1550 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001551 if (sparse)
1552 opCode = OpImageSparseSampleProjImplicitLod;
1553 else
1554 opCode = OpImageSampleProjImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001555 else
Rex Xu48edadf2015-12-31 16:11:41 +08001556 if (sparse)
1557 opCode = OpImageSparseSampleImplicitLod;
1558 else
1559 opCode = OpImageSampleImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001560 }
1561 }
John Kessenich140f3df2015-06-26 16:58:36 -06001562
John Kessenich7355eeb2015-09-14 22:08:12 -06001563 // See if the result type is expecting a smeared result.
1564 // This happens when a legacy shadow*() call is made, which
1565 // gets a vec4 back instead of a float.
1566 Id smearedType = resultType;
1567 if (! isScalarType(resultType)) {
1568 switch (opCode) {
1569 case OpImageSampleDrefImplicitLod:
1570 case OpImageSampleDrefExplicitLod:
1571 case OpImageSampleProjDrefImplicitLod:
1572 case OpImageSampleProjDrefExplicitLod:
1573 resultType = getScalarTypeId(resultType);
1574 break;
1575 default:
1576 break;
1577 }
1578 }
1579
Rex Xu48edadf2015-12-31 16:11:41 +08001580 Id typeId0 = 0;
1581 Id typeId1 = 0;
1582
1583 if (sparse) {
1584 typeId0 = resultType;
1585 typeId1 = getDerefTypeId(parameters.texelOut);
1586 resultType = makeStructResultType(typeId0, typeId1);
1587 }
1588
John Kessenich55e7d112015-11-15 21:33:39 -07001589 // Build the SPIR-V instruction
John Kessenich140f3df2015-06-26 16:58:36 -06001590 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
John Kessenich5e4b1242015-08-06 22:53:06 -06001591 for (int op = 0; op < optArgNum; ++op)
1592 textureInst->addIdOperand(texArgs[op]);
1593 if (optArgNum < numArgs)
1594 textureInst->addImmediateOperand(texArgs[optArgNum]);
1595 for (int op = optArgNum + 1; op < numArgs; ++op)
John Kessenich140f3df2015-06-26 16:58:36 -06001596 textureInst->addIdOperand(texArgs[op]);
1597 setPrecision(textureInst->getResultId(), precision);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001598 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
John Kessenich140f3df2015-06-26 16:58:36 -06001599
John Kessenich7355eeb2015-09-14 22:08:12 -06001600 Id resultId = textureInst->getResultId();
1601
Rex Xu48edadf2015-12-31 16:11:41 +08001602 if (sparse) {
John Kessenich5e801132016-02-15 11:09:46 -07001603 // set capability
1604 addCapability(CapabilitySparseResidency);
1605
Rex Xu48edadf2015-12-31 16:11:41 +08001606 // Decode the return type that was a special structure
1607 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
1608 resultId = createCompositeExtract(resultId, typeId0, 0);
John Kessenich32cfd492016-02-02 12:37:46 -07001609 setPrecision(resultId, precision);
Rex Xu48edadf2015-12-31 16:11:41 +08001610 } else {
1611 // When a smear is needed, do it, as per what was computed
1612 // above when resultType was changed to a scalar type.
1613 if (resultType != smearedType)
1614 resultId = smearScalar(precision, resultId, smearedType);
1615 }
John Kessenich7355eeb2015-09-14 22:08:12 -06001616
1617 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001618}
1619
1620// Comments in header
1621Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)
1622{
John Kessenich5e801132016-02-15 11:09:46 -07001623 // All these need a capability
1624 addCapability(CapabilityImageQuery);
1625
John Kessenich140f3df2015-06-26 16:58:36 -06001626 // Figure out the result type
John Kessenich5e4b1242015-08-06 22:53:06 -06001627 Id resultType = 0;
John Kessenich140f3df2015-06-26 16:58:36 -06001628 switch (opCode) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001629 case OpImageQuerySize:
1630 case OpImageQuerySizeLod:
John Kessenich140f3df2015-06-26 16:58:36 -06001631 {
Mark Adams364c21c2016-01-06 13:41:02 -05001632 int numComponents = 0;
John Kessenich5e4b1242015-08-06 22:53:06 -06001633 switch (getTypeDimensionality(getImageType(parameters.sampler))) {
John Kessenich140f3df2015-06-26 16:58:36 -06001634 case Dim1D:
1635 case DimBuffer:
1636 numComponents = 1;
1637 break;
1638 case Dim2D:
1639 case DimCube:
1640 case DimRect:
John Kessenich50e57562015-12-21 21:21:11 -07001641 case DimSubpassData:
John Kessenich140f3df2015-06-26 16:58:36 -06001642 numComponents = 2;
1643 break;
1644 case Dim3D:
1645 numComponents = 3;
1646 break;
John Kessenich55e7d112015-11-15 21:33:39 -07001647
John Kessenich140f3df2015-06-26 16:58:36 -06001648 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001649 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -06001650 break;
1651 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001652 if (isArrayedImageType(getImageType(parameters.sampler)))
John Kessenich140f3df2015-06-26 16:58:36 -06001653 ++numComponents;
1654 if (numComponents == 1)
1655 resultType = makeIntType(32);
1656 else
1657 resultType = makeVectorType(makeIntType(32), numComponents);
1658
1659 break;
1660 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001661 case OpImageQueryLod:
John Kessenich140f3df2015-06-26 16:58:36 -06001662 resultType = makeVectorType(makeFloatType(32), 2);
1663 break;
John Kessenich5e4b1242015-08-06 22:53:06 -06001664 case OpImageQueryLevels:
1665 case OpImageQuerySamples:
John Kessenich140f3df2015-06-26 16:58:36 -06001666 resultType = makeIntType(32);
1667 break;
1668 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001669 assert(0);
1670 break;
John Kessenich140f3df2015-06-26 16:58:36 -06001671 }
1672
1673 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
1674 query->addIdOperand(parameters.sampler);
1675 if (parameters.coords)
1676 query->addIdOperand(parameters.coords);
1677 if (parameters.lod)
1678 query->addIdOperand(parameters.lod);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001679 buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
John Kessenich140f3df2015-06-26 16:58:36 -06001680
1681 return query->getResultId();
1682}
1683
John Kessenich22118352015-12-21 20:54:09 -07001684// External comments in header.
1685// Operates recursively to visit the composite's hierarchy.
1686Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
John Kessenich140f3df2015-06-26 16:58:36 -06001687{
1688 Id boolType = makeBoolType();
1689 Id valueType = getTypeId(value1);
1690
Mark Adamsd5ac5382016-02-01 19:13:06 -08001691 Id resultId = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001692
John Kessenich22118352015-12-21 20:54:09 -07001693 int numConstituents = getNumTypeConstituents(valueType);
John Kessenich140f3df2015-06-26 16:58:36 -06001694
John Kessenich22118352015-12-21 20:54:09 -07001695 // Scalars and Vectors
1696
1697 if (isScalarType(valueType) || isVectorType(valueType)) {
John Kesseniche23c9842016-01-04 23:49:03 -07001698 assert(valueType == getTypeId(value2));
John Kessenich22118352015-12-21 20:54:09 -07001699 // These just need a single comparison, just have
1700 // to figure out what it is.
John Kessenich140f3df2015-06-26 16:58:36 -06001701 Op op;
John Kessenich22118352015-12-21 20:54:09 -07001702 switch (getMostBasicTypeClass(valueType)) {
1703 case OpTypeFloat:
John Kessenich140f3df2015-06-26 16:58:36 -06001704 op = equal ? OpFOrdEqual : OpFOrdNotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001705 break;
1706 case OpTypeInt:
Mark Adamsd5ac5382016-02-01 19:13:06 -08001707 default:
John Kessenich140f3df2015-06-26 16:58:36 -06001708 op = equal ? OpIEqual : OpINotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001709 break;
1710 case OpTypeBool:
1711 op = equal ? OpLogicalEqual : OpLogicalNotEqual;
1712 precision = NoPrecision;
1713 break;
1714 }
John Kessenich140f3df2015-06-26 16:58:36 -06001715
John Kessenich22118352015-12-21 20:54:09 -07001716 if (isScalarType(valueType)) {
1717 // scalar
1718 resultId = createBinOp(op, boolType, value1, value2);
John Kessenich22118352015-12-21 20:54:09 -07001719 } else {
1720 // vector
1721 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
1722 setPrecision(resultId, precision);
1723 // reduce vector compares...
1724 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
1725 }
John Kessenich140f3df2015-06-26 16:58:36 -06001726
John Kessenich32cfd492016-02-02 12:37:46 -07001727 return setPrecision(resultId, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001728 }
1729
John Kessenich22118352015-12-21 20:54:09 -07001730 // Only structs, arrays, and matrices should be left.
1731 // They share in common the reduction operation across their constituents.
1732 assert(isAggregateType(valueType) || isMatrixType(valueType));
John Kessenich140f3df2015-06-26 16:58:36 -06001733
John Kessenich22118352015-12-21 20:54:09 -07001734 // Compare each pair of constituents
1735 for (int constituent = 0; constituent < numConstituents; ++constituent) {
1736 std::vector<unsigned> indexes(1, constituent);
John Kesseniche23c9842016-01-04 23:49:03 -07001737 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
1738 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
1739 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
1740 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06001741
John Kessenich22118352015-12-21 20:54:09 -07001742 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
John Kessenich140f3df2015-06-26 16:58:36 -06001743
John Kessenich22118352015-12-21 20:54:09 -07001744 if (constituent == 0)
1745 resultId = subResultId;
1746 else
John Kessenich32cfd492016-02-02 12:37:46 -07001747 resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision);
John Kessenich22118352015-12-21 20:54:09 -07001748 }
John Kessenich140f3df2015-06-26 16:58:36 -06001749
John Kessenich22118352015-12-21 20:54:09 -07001750 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001751}
1752
John Kessenich140f3df2015-06-26 16:58:36 -06001753// OpCompositeConstruct
1754Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)
1755{
John Kessenich22118352015-12-21 20:54:09 -07001756 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size()));
John Kessenich140f3df2015-06-26 16:58:36 -06001757
qining27e04a02016-04-14 16:40:20 -04001758 if (generatingOpCodeForSpecConst) {
qining1f2820a2016-04-14 18:34:27 -04001759 // Sometime, even in spec-constant-op mode, the constant composite to be
1760 // constructed may not be a specialization constant.
1761 // e.g.:
1762 // const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
1763 // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
1764 // The second column vector should NOT be spec constant, as it does not contain any spec constants.
1765 // To handle such cases, we check the constituents of the constant vector to determine whether this
1766 // vector should be created as a spec constant.
1767 return makeCompositeConstant(typeId, constituents,
1768 std::any_of(constituents.begin(), constituents.end(),
1769 [&](spv::Id id) { return isSpecConstant(id); }));
qining27e04a02016-04-14 16:40:20 -04001770 }
1771
John Kessenich140f3df2015-06-26 16:58:36 -06001772 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
1773 for (int c = 0; c < (int)constituents.size(); ++c)
1774 op->addIdOperand(constituents[c]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001775 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001776
1777 return op->getResultId();
1778}
1779
1780// Vector or scalar constructor
1781Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1782{
John Kessenich32cfd492016-02-02 12:37:46 -07001783 Id result = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001784 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
1785 unsigned int targetComponent = 0;
1786
1787 // Special case: when calling a vector constructor with a single scalar
1788 // argument, smear the scalar
1789 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
1790 return smearScalar(precision, sources[0], resultTypeId);
1791
1792 Id scalarTypeId = getScalarTypeId(resultTypeId);
1793 std::vector<Id> constituents; // accumulate the arguments for OpCompositeConstruct
1794 for (unsigned int i = 0; i < sources.size(); ++i) {
John Kessenich55e7d112015-11-15 21:33:39 -07001795 assert(! isAggregate(sources[i]));
John Kessenich140f3df2015-06-26 16:58:36 -06001796 unsigned int sourceSize = getNumComponents(sources[i]);
John Kessenich140f3df2015-06-26 16:58:36 -06001797 unsigned int sourcesToUse = sourceSize;
1798 if (sourcesToUse + targetComponent > numTargetComponents)
1799 sourcesToUse = numTargetComponents - targetComponent;
1800
1801 for (unsigned int s = 0; s < sourcesToUse; ++s) {
1802 Id arg = sources[i];
1803 if (sourceSize > 1) {
1804 std::vector<unsigned> swiz;
1805 swiz.push_back(s);
John Kessenich32cfd492016-02-02 12:37:46 -07001806 arg = createRvalueSwizzle(precision, scalarTypeId, arg, swiz);
John Kessenich140f3df2015-06-26 16:58:36 -06001807 }
1808
1809 if (numTargetComponents > 1)
1810 constituents.push_back(arg);
1811 else
1812 result = arg;
1813 ++targetComponent;
1814 }
1815
1816 if (targetComponent >= numTargetComponents)
1817 break;
1818 }
1819
1820 if (constituents.size() > 0)
1821 result = createCompositeConstruct(resultTypeId, constituents);
1822
John Kessenich32cfd492016-02-02 12:37:46 -07001823 return setPrecision(result, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001824}
1825
1826// Comments in header
1827Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1828{
1829 Id componentTypeId = getScalarTypeId(resultTypeId);
1830 int numCols = getTypeNumColumns(resultTypeId);
1831 int numRows = getTypeNumRows(resultTypeId);
1832
iostrowsaf7f1c82016-06-01 16:40:00 +02001833 Instruction* instr = module.getInstruction(componentTypeId);
1834 Id bitCount = instr->getIdOperand(0);
1835
John Kessenich140f3df2015-06-26 16:58:36 -06001836 // Will use a two step process
1837 // 1. make a compile-time 2D array of values
1838 // 2. construct a matrix from that array
1839
1840 // Step 1.
1841
1842 // initialize the array to the identity matrix
1843 Id ids[maxMatrixSize][maxMatrixSize];
iostrowsaf7f1c82016-06-01 16:40:00 +02001844 Id one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
1845 Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
John Kessenich140f3df2015-06-26 16:58:36 -06001846 for (int col = 0; col < 4; ++col) {
1847 for (int row = 0; row < 4; ++row) {
1848 if (col == row)
1849 ids[col][row] = one;
1850 else
1851 ids[col][row] = zero;
1852 }
1853 }
1854
1855 // modify components as dictated by the arguments
1856 if (sources.size() == 1 && isScalar(sources[0])) {
1857 // a single scalar; resets the diagonals
1858 for (int col = 0; col < 4; ++col)
1859 ids[col][col] = sources[0];
1860 } else if (isMatrix(sources[0])) {
1861 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
1862 Id matrix = sources[0];
1863 int minCols = std::min(numCols, getNumColumns(matrix));
1864 int minRows = std::min(numRows, getNumRows(matrix));
1865 for (int col = 0; col < minCols; ++col) {
1866 std::vector<unsigned> indexes;
1867 indexes.push_back(col);
1868 for (int row = 0; row < minRows; ++row) {
1869 indexes.push_back(row);
1870 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
1871 indexes.pop_back();
1872 setPrecision(ids[col][row], precision);
1873 }
1874 }
1875 } else {
1876 // fill in the matrix in column-major order with whatever argument components are available
1877 int row = 0;
1878 int col = 0;
1879
1880 for (int arg = 0; arg < (int)sources.size(); ++arg) {
1881 Id argComp = sources[arg];
1882 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
1883 if (getNumComponents(sources[arg]) > 1) {
1884 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
1885 setPrecision(argComp, precision);
1886 }
1887 ids[col][row++] = argComp;
1888 if (row == numRows) {
1889 row = 0;
1890 col++;
1891 }
1892 }
1893 }
1894 }
1895
1896
1897 // Step 2: Construct a matrix from that array.
1898 // First make the column vectors, then make the matrix.
1899
1900 // make the column vectors
1901 Id columnTypeId = getContainedTypeId(resultTypeId);
1902 std::vector<Id> matrixColumns;
1903 for (int col = 0; col < numCols; ++col) {
1904 std::vector<Id> vectorComponents;
1905 for (int row = 0; row < numRows; ++row)
1906 vectorComponents.push_back(ids[col][row]);
John Kessenich32cfd492016-02-02 12:37:46 -07001907 Id column = createCompositeConstruct(columnTypeId, vectorComponents);
1908 setPrecision(column, precision);
1909 matrixColumns.push_back(column);
John Kessenich140f3df2015-06-26 16:58:36 -06001910 }
1911
1912 // make the matrix
John Kessenich32cfd492016-02-02 12:37:46 -07001913 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001914}
1915
1916// Comments in header
1917Builder::If::If(Id cond, Builder& gb) :
1918 builder(gb),
1919 condition(cond),
1920 elseBlock(0)
1921{
1922 function = &builder.getBuildPoint()->getParent();
1923
1924 // make the blocks, but only put the then-block into the function,
1925 // the else-block and merge-block will be added later, in order, after
1926 // earlier code is emitted
1927 thenBlock = new Block(builder.getUniqueId(), *function);
1928 mergeBlock = new Block(builder.getUniqueId(), *function);
1929
1930 // Save the current block, so that we can add in the flow control split when
1931 // makeEndIf is called.
1932 headerBlock = builder.getBuildPoint();
1933
1934 function->addBlock(thenBlock);
1935 builder.setBuildPoint(thenBlock);
1936}
1937
1938// Comments in header
1939void Builder::If::makeBeginElse()
1940{
1941 // Close out the "then" by having it jump to the mergeBlock
1942 builder.createBranch(mergeBlock);
1943
1944 // Make the first else block and add it to the function
1945 elseBlock = new Block(builder.getUniqueId(), *function);
1946 function->addBlock(elseBlock);
1947
1948 // Start building the else block
1949 builder.setBuildPoint(elseBlock);
1950}
1951
1952// Comments in header
1953void Builder::If::makeEndIf()
1954{
1955 // jump to the merge block
1956 builder.createBranch(mergeBlock);
1957
1958 // Go back to the headerBlock and make the flow control split
1959 builder.setBuildPoint(headerBlock);
John Kessenich55e7d112015-11-15 21:33:39 -07001960 builder.createSelectionMerge(mergeBlock, SelectionControlMaskNone);
John Kessenich140f3df2015-06-26 16:58:36 -06001961 if (elseBlock)
1962 builder.createConditionalBranch(condition, thenBlock, elseBlock);
1963 else
1964 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
1965
1966 // add the merge block to the function
1967 function->addBlock(mergeBlock);
1968 builder.setBuildPoint(mergeBlock);
1969}
1970
1971// Comments in header
1972void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,
1973 std::vector<Block*>& segmentBlocks)
1974{
1975 Function& function = buildPoint->getParent();
1976
1977 // make all the blocks
1978 for (int s = 0; s < numSegments; ++s)
1979 segmentBlocks.push_back(new Block(getUniqueId(), function));
1980
1981 Block* mergeBlock = new Block(getUniqueId(), function);
1982
1983 // make and insert the switch's selection-merge instruction
John Kessenich55e7d112015-11-15 21:33:39 -07001984 createSelectionMerge(mergeBlock, SelectionControlMaskNone);
John Kessenich140f3df2015-06-26 16:58:36 -06001985
1986 // make the switch instruction
1987 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
1988 switchInst->addIdOperand(selector);
Dejan Mircevski454796e2016-01-18 16:18:01 -05001989 auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
1990 switchInst->addIdOperand(defaultOrMerge->getId());
1991 defaultOrMerge->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06001992 for (int i = 0; i < (int)caseValues.size(); ++i) {
1993 switchInst->addImmediateOperand(caseValues[i]);
1994 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
Dejan Mircevski454796e2016-01-18 16:18:01 -05001995 segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06001996 }
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001997 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
John Kessenich140f3df2015-06-26 16:58:36 -06001998
1999 // push the merge block
2000 switchMerges.push(mergeBlock);
2001}
2002
2003// Comments in header
2004void Builder::addSwitchBreak()
2005{
2006 // branch to the top of the merge block stack
2007 createBranch(switchMerges.top());
2008 createAndSetNoPredecessorBlock("post-switch-break");
2009}
2010
2011// Comments in header
2012void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
2013{
2014 int lastSegment = nextSegment - 1;
2015 if (lastSegment >= 0) {
2016 // Close out previous segment by jumping, if necessary, to next segment
2017 if (! buildPoint->isTerminated())
2018 createBranch(segmentBlock[nextSegment]);
2019 }
2020 Block* block = segmentBlock[nextSegment];
2021 block->getParent().addBlock(block);
2022 setBuildPoint(block);
2023}
2024
2025// Comments in header
2026void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
2027{
2028 // Close out previous segment by jumping, if necessary, to next segment
2029 if (! buildPoint->isTerminated())
2030 addSwitchBreak();
2031
2032 switchMerges.top()->getParent().addBlock(switchMerges.top());
2033 setBuildPoint(switchMerges.top());
2034
2035 switchMerges.pop();
2036}
2037
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05002038Block& Builder::makeNewBlock()
2039{
2040 Function& function = buildPoint->getParent();
2041 auto block = new Block(getUniqueId(), function);
2042 function.addBlock(block);
2043 return *block;
2044}
2045
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002046Builder::LoopBlocks& Builder::makeNewLoop()
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05002047{
John Kessenich7f349c72016-07-08 22:09:10 -06002048 // This verbosity is needed to simultaneously get the same behavior
2049 // everywhere (id's in the same order), have a syntax that works
2050 // across lots of versions of C++, have no warnings from pedantic
2051 // compilation modes, and leave the rest of the code alone.
2052 Block& head = makeNewBlock();
2053 Block& body = makeNewBlock();
2054 Block& merge = makeNewBlock();
2055 Block& continue_target = makeNewBlock();
2056 LoopBlocks blocks(head, body, merge, continue_target);
Dejan Mircevski97605c82016-01-20 10:19:25 -05002057 loops.push(blocks);
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002058 return loops.top();
John Kessenich140f3df2015-06-26 16:58:36 -06002059}
2060
2061void Builder::createLoopContinue()
2062{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002063 createBranch(&loops.top().continue_target);
John Kessenich140f3df2015-06-26 16:58:36 -06002064 // Set up a block for dead code.
2065 createAndSetNoPredecessorBlock("post-loop-continue");
2066}
2067
John Kessenich140f3df2015-06-26 16:58:36 -06002068void Builder::createLoopExit()
2069{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002070 createBranch(&loops.top().merge);
John Kessenich140f3df2015-06-26 16:58:36 -06002071 // Set up a block for dead code.
2072 createAndSetNoPredecessorBlock("post-loop-break");
2073}
2074
John Kessenich140f3df2015-06-26 16:58:36 -06002075void Builder::closeLoop()
2076{
John Kessenich140f3df2015-06-26 16:58:36 -06002077 loops.pop();
2078}
2079
2080void Builder::clearAccessChain()
2081{
John Kessenichfa668da2015-09-13 14:46:30 -06002082 accessChain.base = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06002083 accessChain.indexChain.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002084 accessChain.instr = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06002085 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002086 accessChain.component = NoResult;
2087 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002088 accessChain.isRValue = false;
2089}
2090
2091// Comments in header
John Kessenichfa668da2015-09-13 14:46:30 -06002092void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
John Kessenich140f3df2015-06-26 16:58:36 -06002093{
John Kessenichfa668da2015-09-13 14:46:30 -06002094 // swizzles can be stacked in GLSL, but simplified to a single
2095 // one here; the base type doesn't change
2096 if (accessChain.preSwizzleBaseType == NoType)
2097 accessChain.preSwizzleBaseType = preSwizzleBaseType;
2098
John Kessenich140f3df2015-06-26 16:58:36 -06002099 // if needed, propagate the swizzle for the current access chain
2100 if (accessChain.swizzle.size()) {
2101 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
2102 accessChain.swizzle.resize(0);
2103 for (unsigned int i = 0; i < swizzle.size(); ++i) {
2104 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
2105 }
2106 } else
2107 accessChain.swizzle = swizzle;
2108
2109 // determine if we need to track this swizzle anymore
2110 simplifyAccessChainSwizzle();
2111}
2112
2113// Comments in header
2114void Builder::accessChainStore(Id rvalue)
2115{
2116 assert(accessChain.isRValue == false);
2117
John Kessenich55e7d112015-11-15 21:33:39 -07002118 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002119 Id base = collapseAccessChain();
2120
John Kessenichfa668da2015-09-13 14:46:30 -06002121 if (accessChain.swizzle.size() && accessChain.component != NoResult)
Lei Zhang17535f72016-05-04 15:55:59 -04002122 logger->missingFunctionality("simultaneous l-value swizzle and dynamic component selection");
John Kessenich140f3df2015-06-26 16:58:36 -06002123
John Kessenich55e7d112015-11-15 21:33:39 -07002124 // 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 -06002125 // extract and insert elements to perform writeMask and/or swizzle.
2126 Id source = NoResult;
2127 if (accessChain.swizzle.size()) {
2128 Id tempBaseId = createLoad(base);
2129 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);
2130 }
2131
2132 // dynamic component selection
John Kessenichfa668da2015-09-13 14:46:30 -06002133 if (accessChain.component != NoResult) {
John Kessenich140f3df2015-06-26 16:58:36 -06002134 Id tempBaseId = (source == NoResult) ? createLoad(base) : source;
2135 source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);
2136 }
2137
2138 if (source == NoResult)
2139 source = rvalue;
2140
2141 createStore(source, base);
2142}
2143
2144// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07002145Id Builder::accessChainLoad(Decoration precision, Id resultType)
John Kessenich140f3df2015-06-26 16:58:36 -06002146{
2147 Id id;
2148
2149 if (accessChain.isRValue) {
John Kessenich55e7d112015-11-15 21:33:39 -07002150 // transfer access chain, but keep it static, so we can stay in registers
2151 transferAccessChainSwizzle(false);
John Kessenich140f3df2015-06-26 16:58:36 -06002152 if (accessChain.indexChain.size() > 0) {
John Kessenichfa668da2015-09-13 14:46:30 -06002153 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
John Kessenich32cfd492016-02-02 12:37:46 -07002154
John Kessenich140f3df2015-06-26 16:58:36 -06002155 // if all the accesses are constants, we can use OpCompositeExtract
2156 std::vector<unsigned> indexes;
2157 bool constant = true;
2158 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
2159 if (isConstantScalar(accessChain.indexChain[i]))
2160 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
2161 else {
2162 constant = false;
2163 break;
2164 }
2165 }
2166
2167 if (constant)
John Kessenichfa668da2015-09-13 14:46:30 -06002168 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06002169 else {
2170 // make a new function variable for this r-value
2171 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
2172
2173 // store into it
2174 createStore(accessChain.base, lValue);
2175
2176 // move base to the new variable
2177 accessChain.base = lValue;
2178 accessChain.isRValue = false;
2179
2180 // load through the access chain
2181 id = createLoad(collapseAccessChain());
2182 }
John Kessenich32cfd492016-02-02 12:37:46 -07002183 setPrecision(id, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002184 } else
John Kessenich32cfd492016-02-02 12:37:46 -07002185 id = accessChain.base; // no precision, it was set when this was defined
John Kessenich140f3df2015-06-26 16:58:36 -06002186 } else {
John Kessenich55e7d112015-11-15 21:33:39 -07002187 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002188 // load through the access chain
2189 id = createLoad(collapseAccessChain());
John Kessenich32cfd492016-02-02 12:37:46 -07002190 setPrecision(id, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002191 }
2192
2193 // Done, unless there are swizzles to do
John Kessenichfa668da2015-09-13 14:46:30 -06002194 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002195 return id;
2196
John Kessenich140f3df2015-06-26 16:58:36 -06002197 // Do remaining swizzling
2198 // First, static swizzling
2199 if (accessChain.swizzle.size()) {
2200 // static swizzle
John Kessenichfa668da2015-09-13 14:46:30 -06002201 Id swizzledType = getScalarTypeId(getTypeId(id));
John Kessenich140f3df2015-06-26 16:58:36 -06002202 if (accessChain.swizzle.size() > 1)
John Kessenichfa668da2015-09-13 14:46:30 -06002203 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
John Kessenich32cfd492016-02-02 12:37:46 -07002204 id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
John Kessenich140f3df2015-06-26 16:58:36 -06002205 }
2206
2207 // dynamic single-component selection
John Kessenichfa668da2015-09-13 14:46:30 -06002208 if (accessChain.component != NoResult)
John Kessenich32cfd492016-02-02 12:37:46 -07002209 id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002210
2211 return id;
2212}
2213
2214Id Builder::accessChainGetLValue()
2215{
2216 assert(accessChain.isRValue == false);
2217
John Kessenich55e7d112015-11-15 21:33:39 -07002218 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002219 Id lvalue = collapseAccessChain();
2220
2221 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
2222 // extract and insert elements to perform writeMask and/or swizzle. This does not
2223 // go with getting a direct l-value pointer.
2224 assert(accessChain.swizzle.size() == 0);
John Kessenichfa668da2015-09-13 14:46:30 -06002225 assert(accessChain.component == NoResult);
John Kessenich140f3df2015-06-26 16:58:36 -06002226
2227 return lvalue;
2228}
2229
John Kessenich103bef92016-02-08 21:38:15 -07002230// comment in header
2231Id Builder::accessChainGetInferredType()
2232{
2233 // anything to operate on?
2234 if (accessChain.base == NoResult)
2235 return NoType;
2236 Id type = getTypeId(accessChain.base);
2237
2238 // do initial dereference
2239 if (! accessChain.isRValue)
2240 type = getContainedTypeId(type);
2241
2242 // dereference each index
rdb32084e82016-02-23 22:17:38 +01002243 for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
John Kessenich103bef92016-02-08 21:38:15 -07002244 if (isStructType(type))
rdb32084e82016-02-23 22:17:38 +01002245 type = getContainedTypeId(type, getConstantScalar(*it));
John Kessenich103bef92016-02-08 21:38:15 -07002246 else
2247 type = getContainedTypeId(type);
2248 }
2249
2250 // dereference swizzle
2251 if (accessChain.swizzle.size() == 1)
2252 type = getContainedTypeId(type);
2253 else if (accessChain.swizzle.size() > 1)
baldurk227e0262016-02-10 19:41:29 +01002254 type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
John Kessenich103bef92016-02-08 21:38:15 -07002255
2256 // dereference component selection
2257 if (accessChain.component)
2258 type = getContainedTypeId(type);
2259
2260 return type;
2261}
2262
qiningda397332016-03-09 19:54:03 -05002263// comment in header
2264void Builder::eliminateDeadDecorations() {
2265 std::unordered_set<const Block*> reachable_blocks;
2266 std::unordered_set<Id> unreachable_definitions;
2267 // Collect IDs defined in unreachable blocks. For each function, label the
2268 // reachable blocks first. Then for each unreachable block, collect the
2269 // result IDs of the instructions in it.
qining95aa5272016-03-09 21:40:41 -05002270 for (std::vector<Function*>::const_iterator fi = module.getFunctions().cbegin();
2271 fi != module.getFunctions().cend(); fi++) {
2272 Function* f = *fi;
qiningda397332016-03-09 19:54:03 -05002273 Block* entry = f->getEntryBlock();
2274 inReadableOrder(entry, [&reachable_blocks](const Block* b) {
2275 reachable_blocks.insert(b);
2276 });
qining95aa5272016-03-09 21:40:41 -05002277 for (std::vector<Block*>::const_iterator bi = f->getBlocks().cbegin();
2278 bi != f->getBlocks().cend(); bi++) {
2279 Block* b = *bi;
qiningda397332016-03-09 19:54:03 -05002280 if (!reachable_blocks.count(b)) {
qining95aa5272016-03-09 21:40:41 -05002281 for (std::vector<std::unique_ptr<Instruction> >::const_iterator
2282 ii = b->getInstructions().cbegin();
2283 ii != b->getInstructions().cend(); ii++) {
2284 Instruction* i = ii->get();
qiningda397332016-03-09 19:54:03 -05002285 unreachable_definitions.insert(i->getResultId());
2286 }
2287 }
2288 }
2289 }
2290 decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
baldurkbd9f8352016-04-02 13:38:42 +02002291 [&unreachable_definitions](std::unique_ptr<Instruction>& I) -> bool {
qiningda397332016-03-09 19:54:03 -05002292 Instruction* inst = I.get();
2293 Id decoration_id = inst->getIdOperand(0);
2294 return unreachable_definitions.count(decoration_id) != 0;
2295 }),
2296 decorations.end());
2297}
2298
John Kessenich140f3df2015-06-26 16:58:36 -06002299void Builder::dump(std::vector<unsigned int>& out) const
2300{
2301 // Header, before first instructions:
2302 out.push_back(MagicNumber);
2303 out.push_back(Version);
2304 out.push_back(builderNumber);
2305 out.push_back(uniqueId + 1);
2306 out.push_back(0);
2307
John Kessenich55e7d112015-11-15 21:33:39 -07002308 // Capabilities
rdb32084e82016-02-23 22:17:38 +01002309 for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
John Kessenich55e7d112015-11-15 21:33:39 -07002310 Instruction capInst(0, 0, OpCapability);
rdb32084e82016-02-23 22:17:38 +01002311 capInst.addImmediateOperand(*it);
John Kessenich55e7d112015-11-15 21:33:39 -07002312 capInst.dump(out);
2313 }
2314
Rex Xu9d93a232016-05-05 12:30:44 +08002315 for (int e = 0; e < (int)extensions.size(); ++e) {
2316 Instruction extInst(0, 0, OpExtension);
2317 extInst.addStringOperand(extensions[e]);
2318 extInst.dump(out);
2319 }
John Kessenich55e7d112015-11-15 21:33:39 -07002320
2321 dumpInstructions(out, imports);
2322 Instruction memInst(0, 0, OpMemoryModel);
2323 memInst.addImmediateOperand(addressModel);
2324 memInst.addImmediateOperand(memoryModel);
2325 memInst.dump(out);
2326
2327 // Instructions saved up while building:
2328 dumpInstructions(out, entryPoints);
2329 dumpInstructions(out, executionModes);
2330
2331 // Debug instructions
John Kessenich140f3df2015-06-26 16:58:36 -06002332 if (source != SourceLanguageUnknown) {
2333 Instruction sourceInst(0, 0, OpSource);
2334 sourceInst.addImmediateOperand(source);
2335 sourceInst.addImmediateOperand(sourceVersion);
2336 sourceInst.dump(out);
2337 }
Rex Xu9d93a232016-05-05 12:30:44 +08002338 for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
2339 Instruction sourceExtInst(0, 0, OpSourceExtension);
2340 sourceExtInst.addStringOperand(sourceExtensions[e]);
2341 sourceExtInst.dump(out);
John Kessenich140f3df2015-06-26 16:58:36 -06002342 }
John Kessenich140f3df2015-06-26 16:58:36 -06002343 dumpInstructions(out, names);
2344 dumpInstructions(out, lines);
John Kessenich55e7d112015-11-15 21:33:39 -07002345
2346 // Annotation instructions
John Kessenich140f3df2015-06-26 16:58:36 -06002347 dumpInstructions(out, decorations);
John Kessenich55e7d112015-11-15 21:33:39 -07002348
John Kessenich140f3df2015-06-26 16:58:36 -06002349 dumpInstructions(out, constantsTypesGlobals);
2350 dumpInstructions(out, externals);
2351
2352 // The functions
2353 module.dump(out);
2354}
2355
2356//
2357// Protected methods.
2358//
2359
John Kessenich55e7d112015-11-15 21:33:39 -07002360// Turn the described access chain in 'accessChain' into an instruction
2361// computing its address. This *cannot* include complex swizzles, which must
2362// be handled after this is called, but it does include swizzles that select
2363// an individual element, as a single address of a scalar type can be
2364// computed by an OpAccessChain instruction.
John Kessenich140f3df2015-06-26 16:58:36 -06002365Id Builder::collapseAccessChain()
2366{
John Kessenich140f3df2015-06-26 16:58:36 -06002367 assert(accessChain.isRValue == false);
2368
2369 if (accessChain.indexChain.size() > 0) {
2370 if (accessChain.instr == 0) {
2371 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
2372 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
2373 }
2374
2375 return accessChain.instr;
2376 } else
2377 return accessChain.base;
John Kessenich55e7d112015-11-15 21:33:39 -07002378
2379 // note that non-trivial swizzling is left pending...
John Kessenich140f3df2015-06-26 16:58:36 -06002380}
2381
John Kessenich55e7d112015-11-15 21:33:39 -07002382// clear out swizzle if it is redundant, that is reselecting the same components
2383// that would be present without the swizzle.
John Kessenich140f3df2015-06-26 16:58:36 -06002384void Builder::simplifyAccessChainSwizzle()
2385{
2386 // If the swizzle has fewer components than the vector, it is subsetting, and must stay
2387 // to preserve that fact.
John Kessenichfa668da2015-09-13 14:46:30 -06002388 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
John Kessenich140f3df2015-06-26 16:58:36 -06002389 return;
2390
2391 // if components are out of order, it is a swizzle
2392 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
2393 if (i != accessChain.swizzle[i])
2394 return;
2395 }
2396
2397 // otherwise, there is no need to track this swizzle
2398 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002399 if (accessChain.component == NoResult)
2400 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002401}
2402
John Kessenich55e7d112015-11-15 21:33:39 -07002403// To the extent any swizzling can become part of the chain
2404// of accesses instead of a post operation, make it so.
Eric Engestrom6a6d6dd2016-04-03 01:17:13 +01002405// If 'dynamic' is true, include transferring a non-static component index,
John Kessenich55e7d112015-11-15 21:33:39 -07002406// otherwise, only transfer static indexes.
2407//
2408// Also, Boolean vectors are likely to be special. While
2409// for external storage, they should only be integer types,
2410// function-local bool vectors could use sub-word indexing,
2411// so keep that as a separate Insert/Extract on a loaded vector.
2412void Builder::transferAccessChainSwizzle(bool dynamic)
John Kessenich140f3df2015-06-26 16:58:36 -06002413{
John Kessenich55e7d112015-11-15 21:33:39 -07002414 // too complex?
2415 if (accessChain.swizzle.size() > 1)
John Kessenich140f3df2015-06-26 16:58:36 -06002416 return;
2417
John Kessenich55e7d112015-11-15 21:33:39 -07002418 // non existent?
2419 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002420 return;
2421
John Kessenich55e7d112015-11-15 21:33:39 -07002422 // single component...
2423
2424 // skip doing it for Boolean vectors
2425 if (isBoolType(getContainedTypeId(accessChain.preSwizzleBaseType)))
2426 return;
2427
2428 if (accessChain.swizzle.size() == 1) {
2429 // handle static component
John Kessenich140f3df2015-06-26 16:58:36 -06002430 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
John Kessenich55e7d112015-11-15 21:33:39 -07002431 accessChain.swizzle.clear();
2432 // note, the only valid remaining dynamic access would be to this one
2433 // component, so don't bother even looking at accessChain.component
2434 accessChain.preSwizzleBaseType = NoType;
2435 accessChain.component = NoResult;
2436 } else if (dynamic && accessChain.component != NoResult) {
2437 // handle dynamic component
John Kessenich140f3df2015-06-26 16:58:36 -06002438 accessChain.indexChain.push_back(accessChain.component);
John Kessenich55e7d112015-11-15 21:33:39 -07002439 accessChain.preSwizzleBaseType = NoType;
2440 accessChain.component = NoResult;
2441 }
John Kessenich140f3df2015-06-26 16:58:36 -06002442}
2443
2444// Utility method for creating a new block and setting the insert point to
2445// be in it. This is useful for flow-control operations that need a "dummy"
2446// block proceeding them (e.g. instructions after a discard, etc).
2447void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
2448{
2449 Block* block = new Block(getUniqueId(), buildPoint->getParent());
2450 block->setUnreachable();
2451 buildPoint->getParent().addBlock(block);
2452 setBuildPoint(block);
2453
2454 //if (name)
2455 // addName(block->getId(), name);
2456}
2457
2458// Comments in header
2459void Builder::createBranch(Block* block)
2460{
2461 Instruction* branch = new Instruction(OpBranch);
2462 branch->addIdOperand(block->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002463 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002464 block->addPredecessor(buildPoint);
2465}
2466
John Kessenich55e7d112015-11-15 21:33:39 -07002467void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
John Kessenich140f3df2015-06-26 16:58:36 -06002468{
John Kessenich55e7d112015-11-15 21:33:39 -07002469 Instruction* merge = new Instruction(OpSelectionMerge);
John Kessenich140f3df2015-06-26 16:58:36 -06002470 merge->addIdOperand(mergeBlock->getId());
2471 merge->addImmediateOperand(control);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002472 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich140f3df2015-06-26 16:58:36 -06002473}
2474
John Kessenich55e7d112015-11-15 21:33:39 -07002475void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control)
2476{
2477 Instruction* merge = new Instruction(OpLoopMerge);
2478 merge->addIdOperand(mergeBlock->getId());
2479 merge->addIdOperand(continueBlock->getId());
2480 merge->addImmediateOperand(control);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002481 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich55e7d112015-11-15 21:33:39 -07002482}
2483
John Kessenich140f3df2015-06-26 16:58:36 -06002484void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
2485{
2486 Instruction* branch = new Instruction(OpBranchConditional);
2487 branch->addIdOperand(condition);
2488 branch->addIdOperand(thenBlock->getId());
2489 branch->addIdOperand(elseBlock->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002490 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002491 thenBlock->addPredecessor(buildPoint);
2492 elseBlock->addPredecessor(buildPoint);
2493}
2494
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002495void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
John Kessenich140f3df2015-06-26 16:58:36 -06002496{
2497 for (int i = 0; i < (int)instructions.size(); ++i) {
2498 instructions[i]->dump(out);
2499 }
2500}
2501
John Kessenich140f3df2015-06-26 16:58:36 -06002502}; // end spv namespace