2 //Copyright (C) 2014 LunarG, Inc.
\r
4 //All rights reserved.
\r
6 //Redistribution and use in source and binary forms, with or without
\r
7 //modification, are permitted provided that the following conditions
\r
10 // Redistributions of source code must retain the above copyright
\r
11 // notice, this list of conditions and the following disclaimer.
\r
13 // Redistributions in binary form must reproduce the above
\r
14 // copyright notice, this list of conditions and the following
\r
15 // disclaimer in the documentation and/or other materials provided
\r
16 // with the distribution.
\r
18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
\r
19 // contributors may be used to endorse or promote products derived
\r
20 // from this software without specific prior written permission.
\r
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\r
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
\r
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
\r
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
\r
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
\r
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
\r
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
\r
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\r
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
\r
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
\r
33 //POSSIBILITY OF SUCH DAMAGE.
\r
36 // Author: John Kessenich, LunarG
\r
40 // Helper for making SPIR-V IR. Generally, this is documented in the header
\r
48 #include "SpvBuilder.h"
\r
56 const int SpvBuilderMagic = 0xBB;
\r
58 Builder::Builder(unsigned int userNumber) :
\r
59 source(SourceLanguageUnknown),
\r
61 addressModel(AddressingModelLogical),
\r
62 memoryModel(MemoryModelGLSL450),
\r
63 builderNumber(userNumber << 16 | SpvBuilderMagic),
\r
76 Id Builder::import(const char* name)
\r
78 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
\r
79 import->addStringOperand(name);
\r
81 imports.push_back(import);
\r
82 return import->getResultId();
\r
85 // For creating new groupedTypes (will return old type if the requested one was already made).
\r
86 Id Builder::makeVoidType()
\r
89 if (groupedTypes[OpTypeVoid].size() == 0) {
\r
90 type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
\r
91 groupedTypes[OpTypeVoid].push_back(type);
\r
92 constantsTypesGlobals.push_back(type);
\r
93 module.mapInstruction(type);
\r
95 type = groupedTypes[OpTypeVoid].back();
\r
97 return type->getResultId();
\r
100 Id Builder::makeBoolType()
\r
103 if (groupedTypes[OpTypeBool].size() == 0) {
\r
104 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
\r
105 groupedTypes[OpTypeBool].push_back(type);
\r
106 constantsTypesGlobals.push_back(type);
\r
107 module.mapInstruction(type);
\r
109 type = groupedTypes[OpTypeBool].back();
\r
111 return type->getResultId();
\r
114 Id Builder::makePointer(StorageClass storageClass, Id pointee)
\r
118 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
\r
119 type = groupedTypes[OpTypePointer][t];
\r
120 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
\r
121 type->getIdOperand(1) == pointee)
\r
122 return type->getResultId();
\r
125 // not found, make it
\r
126 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
\r
127 type->addImmediateOperand(storageClass);
\r
128 type->addIdOperand(pointee);
\r
129 groupedTypes[OpTypePointer].push_back(type);
\r
130 constantsTypesGlobals.push_back(type);
\r
131 module.mapInstruction(type);
\r
133 return type->getResultId();
\r
136 Id Builder::makeIntegerType(int width, bool hasSign)
\r
140 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
\r
141 type = groupedTypes[OpTypeInt][t];
\r
142 if (type->getImmediateOperand(0) == (unsigned)width &&
\r
143 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
\r
144 return type->getResultId();
\r
147 // not found, make it
\r
148 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
\r
149 type->addImmediateOperand(width);
\r
150 type->addImmediateOperand(hasSign ? 1 : 0);
\r
151 groupedTypes[OpTypeInt].push_back(type);
\r
152 constantsTypesGlobals.push_back(type);
\r
153 module.mapInstruction(type);
\r
155 return type->getResultId();
\r
158 Id Builder::makeFloatType(int width)
\r
162 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
\r
163 type = groupedTypes[OpTypeFloat][t];
\r
164 if (type->getImmediateOperand(0) == (unsigned)width)
\r
165 return type->getResultId();
\r
168 // not found, make it
\r
169 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
\r
170 type->addImmediateOperand(width);
\r
171 groupedTypes[OpTypeFloat].push_back(type);
\r
172 constantsTypesGlobals.push_back(type);
\r
173 module.mapInstruction(type);
\r
175 return type->getResultId();
\r
178 Id Builder::makeStructType(std::vector<Id>& members, const char* name)
\r
180 // not found, make it
\r
181 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
\r
182 for (int op = 0; op < (int)members.size(); ++op)
\r
183 type->addIdOperand(members[op]);
\r
184 groupedTypes[OpTypeStruct].push_back(type);
\r
185 constantsTypesGlobals.push_back(type);
\r
186 module.mapInstruction(type);
\r
187 addName(type->getResultId(), name);
\r
189 return type->getResultId();
\r
192 Id Builder::makeVectorType(Id component, int size)
\r
196 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
\r
197 type = groupedTypes[OpTypeVector][t];
\r
198 if (type->getIdOperand(0) == component &&
\r
199 type->getImmediateOperand(1) == (unsigned)size)
\r
200 return type->getResultId();
\r
203 // not found, make it
\r
204 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
\r
205 type->addIdOperand(component);
\r
206 type->addImmediateOperand(size);
\r
207 groupedTypes[OpTypeVector].push_back(type);
\r
208 constantsTypesGlobals.push_back(type);
\r
209 module.mapInstruction(type);
\r
211 return type->getResultId();
\r
214 Id Builder::makeMatrixType(Id component, int cols, int rows)
\r
216 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
\r
218 Id column = makeVectorType(component, rows);
\r
222 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
\r
223 type = groupedTypes[OpTypeMatrix][t];
\r
224 if (type->getIdOperand(0) == column &&
\r
225 type->getImmediateOperand(1) == (unsigned)cols)
\r
226 return type->getResultId();
\r
229 // not found, make it
\r
230 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
\r
231 type->addIdOperand(column);
\r
232 type->addImmediateOperand(cols);
\r
233 groupedTypes[OpTypeMatrix].push_back(type);
\r
234 constantsTypesGlobals.push_back(type);
\r
235 module.mapInstruction(type);
\r
237 return type->getResultId();
\r
240 Id Builder::makeArrayType(Id element, unsigned size)
\r
242 // First, we need a constant instruction for the size
\r
243 Id sizeId = makeUintConstant(size);
\r
245 // try to find existing type
\r
247 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
\r
248 type = groupedTypes[OpTypeArray][t];
\r
249 if (type->getIdOperand(0) == element &&
\r
250 type->getIdOperand(1) == sizeId)
\r
251 return type->getResultId();
\r
254 // not found, make it
\r
255 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
\r
256 type->addIdOperand(element);
\r
257 type->addIdOperand(sizeId);
\r
258 groupedTypes[OpTypeArray].push_back(type);
\r
259 constantsTypesGlobals.push_back(type);
\r
260 module.mapInstruction(type);
\r
262 return type->getResultId();
\r
265 Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
\r
269 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
\r
270 type = groupedTypes[OpTypeFunction][t];
\r
271 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
\r
273 bool mismatch = false;
\r
274 for (int p = 0; p < (int)paramTypes.size(); ++p) {
\r
275 if (paramTypes[p] != type->getIdOperand(p + 1)) {
\r
281 return type->getResultId();
\r
284 // not found, make it
\r
285 type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
\r
286 type->addIdOperand(returnType);
\r
287 for (int p = 0; p < (int)paramTypes.size(); ++p)
\r
288 type->addIdOperand(paramTypes[p]);
\r
289 groupedTypes[OpTypeFunction].push_back(type);
\r
290 constantsTypesGlobals.push_back(type);
\r
291 module.mapInstruction(type);
\r
293 return type->getResultId();
\r
296 Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)
\r
300 for (int t = 0; t < (int)groupedTypes[OpTypeSampler].size(); ++t) {
\r
301 type = groupedTypes[OpTypeSampler][t];
\r
302 if (type->getIdOperand(0) == sampledType &&
\r
303 type->getImmediateOperand(1) == (unsigned int)dim &&
\r
304 type->getImmediateOperand(2) == content &&
\r
305 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
\r
306 type->getImmediateOperand(4) == ( shadow ? 1u : 0u) &&
\r
307 type->getImmediateOperand(5) == ( ms ? 1u : 0u))
\r
308 return type->getResultId();
\r
311 // not found, make it
\r
312 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
\r
313 type->addIdOperand(sampledType);
\r
314 type->addImmediateOperand( dim);
\r
315 type->addImmediateOperand(content);
\r
316 type->addImmediateOperand(arrayed ? 1 : 0);
\r
317 type->addImmediateOperand( shadow ? 1 : 0);
\r
318 type->addImmediateOperand( ms ? 1 : 0);
\r
320 groupedTypes[OpTypeSampler].push_back(type);
\r
321 constantsTypesGlobals.push_back(type);
\r
322 module.mapInstruction(type);
\r
324 return type->getResultId();
\r
327 Id Builder::getDerefTypeId(Id resultId) const
\r
329 Id typeId = getTypeId(resultId);
\r
330 assert(isPointerType(typeId));
\r
332 return module.getInstruction(typeId)->getImmediateOperand(1);
\r
335 Op Builder::getMostBasicTypeClass(Id typeId) const
\r
337 Instruction* instr = module.getInstruction(typeId);
\r
339 Op typeClass = instr->getOpCode();
\r
351 case OpTypeRuntimeArray:
\r
352 return getMostBasicTypeClass(instr->getIdOperand(0));
\r
353 case OpTypePointer:
\r
354 return getMostBasicTypeClass(instr->getIdOperand(1));
\r
356 MissingFunctionality("getMostBasicTypeClass");
\r
357 return OpTypeFloat;
\r
361 int Builder::getNumTypeComponents(Id typeId) const
\r
363 Instruction* instr = module.getInstruction(typeId);
\r
365 switch (instr->getOpCode())
\r
373 return instr->getImmediateOperand(1);
\r
375 MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");
\r
380 // Return the lowest-level type of scalar that an homogeneous composite is made out of.
\r
381 // Typically, this is just to find out if something is made out of ints or floats.
\r
382 // However, it includes returning a structure, if say, it is an array of structure.
\r
383 Id Builder::getScalarTypeId(Id typeId) const
\r
385 Instruction* instr = module.getInstruction(typeId);
\r
387 Op typeClass = instr->getOpCode();
\r
395 return instr->getResultId();
\r
399 case OpTypeRuntimeArray:
\r
400 case OpTypePointer:
\r
401 return getScalarTypeId(getContainedTypeId(typeId));
\r
403 MissingFunctionality("getScalarTypeId");
\r
408 // Return the type of 'member' of a composite.
\r
409 Id Builder::getContainedTypeId(Id typeId, int member) const
\r
411 Instruction* instr = module.getInstruction(typeId);
\r
413 Op typeClass = instr->getOpCode();
\r
419 case OpTypeRuntimeArray:
\r
420 return instr->getIdOperand(0);
\r
421 case OpTypePointer:
\r
422 return instr->getIdOperand(1);
\r
424 return instr->getIdOperand(member);
\r
426 MissingFunctionality("getContainedTypeId");
\r
431 // Return the immediately contained type of a given composite type.
\r
432 Id Builder::getContainedTypeId(Id typeId) const
\r
434 return getContainedTypeId(typeId, 0);
\r
437 // See if a scalar constant of this type has already been created, so it
\r
438 // can be reused rather than duplicated. (Required by the specification).
\r
439 Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const
\r
441 Instruction* constant;
\r
442 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
\r
443 constant = groupedConstants[typeClass][i];
\r
444 if (constant->getNumOperands() == 1 &&
\r
445 constant->getTypeId() == typeId &&
\r
446 constant->getImmediateOperand(0) == value)
\r
447 return constant->getResultId();
\r
453 // Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').
\r
454 Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const
\r
456 Instruction* constant;
\r
457 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
\r
458 constant = groupedConstants[typeClass][i];
\r
459 if (constant->getNumOperands() == 2 &&
\r
460 constant->getTypeId() == typeId &&
\r
461 constant->getImmediateOperand(0) == v1 &&
\r
462 constant->getImmediateOperand(1) == v2)
\r
463 return constant->getResultId();
\r
469 Id Builder::makeBoolConstant(bool b)
\r
471 Id typeId = makeBoolType();
\r
472 Instruction* constant;
\r
474 // See if we already made it
\r
476 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
\r
477 constant = groupedConstants[OpTypeBool][i];
\r
478 if (constant->getTypeId() == typeId &&
\r
479 (b ? (constant->getOpCode() == OpConstantTrue) :
\r
480 (constant->getOpCode() == OpConstantFalse)))
\r
481 existing = constant->getResultId();
\r
488 Instruction* c = new Instruction(getUniqueId(), typeId, b ? OpConstantTrue : OpConstantFalse);
\r
489 constantsTypesGlobals.push_back(c);
\r
490 groupedConstants[OpTypeBool].push_back(c);
\r
491 module.mapInstruction(c);
\r
493 return c->getResultId();
\r
496 Id Builder::makeIntConstant(Id typeId, unsigned value)
\r
498 Id existing = findScalarConstant(OpTypeInt, typeId, value);
\r
502 Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
\r
503 c->addImmediateOperand(value);
\r
504 constantsTypesGlobals.push_back(c);
\r
505 groupedConstants[OpTypeInt].push_back(c);
\r
506 module.mapInstruction(c);
\r
508 return c->getResultId();
\r
511 Id Builder::makeFloatConstant(float f)
\r
513 Id typeId = makeFloatType(32);
\r
514 unsigned value = *(unsigned int*)&f;
\r
515 Id existing = findScalarConstant(OpTypeFloat, typeId, value);
\r
519 Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
\r
520 c->addImmediateOperand(value);
\r
521 constantsTypesGlobals.push_back(c);
\r
522 groupedConstants[OpTypeFloat].push_back(c);
\r
523 module.mapInstruction(c);
\r
525 return c->getResultId();
\r
528 Id Builder::makeDoubleConstant(double d)
\r
530 Id typeId = makeFloatType(64);
\r
531 unsigned long long value = *(unsigned long long*)&d;
\r
532 unsigned op1 = value & 0xFFFFFFFF;
\r
533 unsigned op2 = value >> 32;
\r
534 Id existing = findScalarConstant(OpTypeFloat, typeId, op1, op2);
\r
538 Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
\r
539 c->addImmediateOperand(op1);
\r
540 c->addImmediateOperand(op2);
\r
541 constantsTypesGlobals.push_back(c);
\r
542 groupedConstants[OpTypeFloat].push_back(c);
\r
543 module.mapInstruction(c);
\r
545 return c->getResultId();
\r
548 Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
\r
550 Instruction* constant = 0;
\r
551 bool found = false;
\r
552 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
\r
553 constant = groupedConstants[typeClass][i];
\r
556 if (constant->getNumOperands() != (int)comps.size())
\r
560 bool mismatch = false;
\r
561 for (int op = 0; op < constant->getNumOperands(); ++op) {
\r
562 if (constant->getIdOperand(op) != comps[op]) {
\r
573 return found ? constant->getResultId() : NoResult;
\r
576 // Comments in header
\r
577 Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
\r
580 Op typeClass = getTypeClass(typeId);
\r
582 switch (typeClass) {
\r
589 MissingFunctionality("Constant composite type in Builder");
\r
590 return makeFloatConstant(0.0);
\r
593 Id existing = findCompositeConstant(typeClass, members);
\r
597 Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);
\r
598 for (int op = 0; op < (int)members.size(); ++op)
\r
599 c->addIdOperand(members[op]);
\r
600 constantsTypesGlobals.push_back(c);
\r
601 groupedConstants[typeClass].push_back(c);
\r
602 module.mapInstruction(c);
\r
604 return c->getResultId();
\r
607 void Builder::addEntryPoint(ExecutionModel model, Function* function)
\r
609 Instruction* entryPoint = new Instruction(OpEntryPoint);
\r
610 entryPoint->addImmediateOperand(model);
\r
611 entryPoint->addIdOperand(function->getId());
\r
613 entryPoints.push_back(entryPoint);
\r
616 void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value)
\r
618 // TODO: handle multiple optional arguments
\r
619 Instruction* instr = new Instruction(OpExecutionMode);
\r
620 instr->addIdOperand(entryPoint->getId());
\r
621 instr->addImmediateOperand(mode);
\r
623 instr->addImmediateOperand(value);
\r
625 executionModes.push_back(instr);
\r
628 void Builder::addName(Id id, const char* string)
\r
630 Instruction* name = new Instruction(OpName);
\r
631 name->addIdOperand(id);
\r
632 name->addStringOperand(string);
\r
634 names.push_back(name);
\r
637 void Builder::addMemberName(Id id, int memberNumber, const char* string)
\r
639 Instruction* name = new Instruction(OpMemberName);
\r
640 name->addIdOperand(id);
\r
641 name->addImmediateOperand(memberNumber);
\r
642 name->addStringOperand(string);
\r
644 names.push_back(name);
\r
647 void Builder::addLine(Id target, Id fileName, int lineNum, int column)
\r
649 Instruction* line = new Instruction(OpLine);
\r
650 line->addIdOperand(target);
\r
651 line->addIdOperand(fileName);
\r
652 line->addImmediateOperand(lineNum);
\r
653 line->addImmediateOperand(column);
\r
655 lines.push_back(line);
\r
658 void Builder::addDecoration(Id id, Decoration decoration, int num)
\r
660 Instruction* dec = new Instruction(OpDecorate);
\r
661 dec->addIdOperand(id);
\r
662 dec->addImmediateOperand(decoration);
\r
664 dec->addImmediateOperand(num);
\r
666 decorations.push_back(dec);
\r
669 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
\r
671 Instruction* dec = new Instruction(OpMemberDecorate);
\r
672 dec->addIdOperand(id);
\r
673 dec->addImmediateOperand(member);
\r
674 dec->addImmediateOperand(decoration);
\r
676 dec->addImmediateOperand(num);
\r
678 decorations.push_back(dec);
\r
681 // Comments in header
\r
682 Function* Builder::makeMain()
\r
684 assert(! mainFunction);
\r
687 std::vector<Id> params;
\r
689 mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);
\r
690 stageExit = new Block(getUniqueId(), *mainFunction);
\r
692 return mainFunction;
\r
695 // Comments in header
\r
696 void Builder::closeMain()
\r
698 setBuildPoint(stageExit);
\r
699 stageExit->addInstruction(new Instruction(NoResult, NoType, OpReturn));
\r
700 mainFunction->addBlock(stageExit);
\r
703 // Comments in header
\r
704 Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)
\r
706 Id typeId = makeFunctionType(returnType, paramTypes);
\r
707 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds(paramTypes.size());
\r
708 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
\r
711 *entry = new Block(getUniqueId(), *function);
\r
712 function->addBlock(*entry);
\r
713 setBuildPoint(*entry);
\r
717 addName(function->getId(), name);
\r
722 // Comments in header
\r
723 void Builder::makeReturn(bool implicit, Id retVal, bool isMain)
\r
725 if (isMain && retVal)
\r
726 MissingFunctionality("return value from main()");
\r
729 createBranch(stageExit);
\r
731 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
\r
732 inst->addIdOperand(retVal);
\r
733 buildPoint->addInstruction(inst);
\r
735 buildPoint->addInstruction(new Instruction(NoResult, NoType, OpReturn));
\r
738 createAndSetNoPredecessorBlock("post-return");
\r
741 // Comments in header
\r
742 void Builder::leaveFunction(bool main)
\r
744 Block* block = buildPoint;
\r
745 Function& function = buildPoint->getParent();
\r
748 // If our function did not contain a return, add a return void now.
\r
749 if (! block->isTerminated()) {
\r
751 // Whether we're in an unreachable (non-entry) block.
\r
752 bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;
\r
755 // Given that this block is at the end of a function, it must be right after an
\r
756 // explicit return, just remove it.
\r
757 function.popBlock(block);
\r
759 makeMainReturn(true);
\r
761 // We're get a return instruction at the end of the current block,
\r
762 // which for a non-void function is really error recovery (?), as the source
\r
763 // being translated should have had an explicit return, which would have been
\r
764 // followed by an unreachable block, which was handled above.
\r
765 if (function.getReturnType() == makeVoidType())
\r
768 Id retStorage = createVariable(StorageClassFunction, function.getReturnType(), "dummyReturn");
\r
769 Id retValue = createLoad(retStorage);
\r
770 makeReturn(true, retValue);
\r
779 // Comments in header
\r
780 void Builder::makeDiscard()
\r
782 buildPoint->addInstruction(new Instruction(OpKill));
\r
783 createAndSetNoPredecessorBlock("post-discard");
\r
786 // Comments in header
\r
787 Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
\r
789 Id pointerType = makePointer(storageClass, type);
\r
790 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
\r
791 inst->addImmediateOperand(storageClass);
\r
793 switch (storageClass) {
\r
794 case StorageClassUniformConstant:
\r
795 case StorageClassUniform:
\r
796 case StorageClassInput:
\r
797 case StorageClassOutput:
\r
798 case StorageClassWorkgroupLocal:
\r
799 case StorageClassPrivateGlobal:
\r
800 case StorageClassWorkgroupGlobal:
\r
801 constantsTypesGlobals.push_back(inst);
\r
802 module.mapInstruction(inst);
\r
805 case StorageClassFunction:
\r
806 // Validation rules require the declaration in the entry block
\r
807 buildPoint->getParent().addLocalVariable(inst);
\r
811 MissingFunctionality("storage class in createVariable");
\r
816 addName(inst->getResultId(), name);
\r
818 return inst->getResultId();
\r
821 // Comments in header
\r
822 void Builder::createStore(Id rValue, Id lValue)
\r
824 Instruction* store = new Instruction(OpStore);
\r
825 store->addIdOperand(lValue);
\r
826 store->addIdOperand(rValue);
\r
827 buildPoint->addInstruction(store);
\r
830 // Comments in header
\r
831 Id Builder::createLoad(Id lValue)
\r
833 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
\r
834 load->addIdOperand(lValue);
\r
835 buildPoint->addInstruction(load);
\r
837 return load->getResultId();
\r
840 // Comments in header
\r
841 Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)
\r
843 // Figure out the final resulting type.
\r
844 spv::Id typeId = getTypeId(base);
\r
845 assert(isPointerType(typeId) && offsets.size() > 0);
\r
846 typeId = getContainedTypeId(typeId);
\r
847 for (int i = 0; i < (int)offsets.size(); ++i) {
\r
848 if (isStructType(typeId)) {
\r
849 assert(isConstantScalar(offsets[i]));
\r
850 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
\r
852 typeId = getContainedTypeId(typeId, offsets[i]);
\r
854 typeId = makePointer(storageClass, typeId);
\r
856 // Make the instruction
\r
857 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
\r
858 chain->addIdOperand(base);
\r
859 for (int i = 0; i < (int)offsets.size(); ++i)
\r
860 chain->addIdOperand(offsets[i]);
\r
861 buildPoint->addInstruction(chain);
\r
863 return chain->getResultId();
\r
866 Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
\r
868 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
\r
869 extract->addIdOperand(composite);
\r
870 extract->addImmediateOperand(index);
\r
871 buildPoint->addInstruction(extract);
\r
873 return extract->getResultId();
\r
876 Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)
\r
878 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
\r
879 extract->addIdOperand(composite);
\r
880 for (int i = 0; i < (int)indexes.size(); ++i)
\r
881 extract->addImmediateOperand(indexes[i]);
\r
882 buildPoint->addInstruction(extract);
\r
884 return extract->getResultId();
\r
887 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
\r
889 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
\r
890 insert->addIdOperand(object);
\r
891 insert->addIdOperand(composite);
\r
892 insert->addImmediateOperand(index);
\r
893 buildPoint->addInstruction(insert);
\r
895 return insert->getResultId();
\r
898 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)
\r
900 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
\r
901 insert->addIdOperand(object);
\r
902 insert->addIdOperand(composite);
\r
903 for (int i = 0; i < (int)indexes.size(); ++i)
\r
904 insert->addImmediateOperand(indexes[i]);
\r
905 buildPoint->addInstruction(insert);
\r
907 return insert->getResultId();
\r
910 // An opcode that has no operands, no result id, and no type
\r
911 void Builder::createNoResultOp(Op opCode)
\r
913 Instruction* op = new Instruction(opCode);
\r
914 buildPoint->addInstruction(op);
\r
917 // An opcode that has one operand, no result id, and no type
\r
918 void Builder::createNoResultOp(Op opCode, Id operand)
\r
920 Instruction* op = new Instruction(opCode);
\r
921 op->addIdOperand(operand);
\r
922 buildPoint->addInstruction(op);
\r
925 void Builder::createControlBarrier(unsigned executionScope)
\r
927 Instruction* op = new Instruction(OpControlBarrier);
\r
928 op->addImmediateOperand(executionScope);
\r
929 buildPoint->addInstruction(op);
\r
932 void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
\r
934 Instruction* op = new Instruction(OpMemoryBarrier);
\r
935 op->addImmediateOperand(executionScope);
\r
936 op->addImmediateOperand(memorySemantics);
\r
937 buildPoint->addInstruction(op);
\r
940 // An opcode that has one operands, a result id, and a type
\r
941 Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
\r
943 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
\r
944 op->addIdOperand(operand);
\r
945 buildPoint->addInstruction(op);
\r
947 return op->getResultId();
\r
950 Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
\r
952 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
\r
953 op->addIdOperand(left);
\r
954 op->addIdOperand(right);
\r
955 buildPoint->addInstruction(op);
\r
957 return op->getResultId();
\r
960 Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
\r
962 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
\r
963 op->addIdOperand(op1);
\r
964 op->addIdOperand(op2);
\r
965 op->addIdOperand(op3);
\r
966 buildPoint->addInstruction(op);
\r
968 return op->getResultId();
\r
971 Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
\r
973 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
\r
974 op->addIdOperand(op1);
\r
975 op->addIdOperand(op2);
\r
976 op->addIdOperand(op3);
\r
977 buildPoint->addInstruction(op);
\r
979 return op->getResultId();
\r
982 Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)
\r
984 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
\r
985 op->addIdOperand(function->getId());
\r
986 for (int a = 0; a < (int)args.size(); ++a)
\r
987 op->addIdOperand(args[a]);
\r
988 buildPoint->addInstruction(op);
\r
990 return op->getResultId();
\r
993 // Comments in header
\r
994 Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)
\r
996 if (channels.size() == 1)
\r
997 return createCompositeExtract(source, typeId, channels.front());
\r
999 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
\r
1000 swizzle->addIdOperand(source);
\r
1001 swizzle->addIdOperand(source);
\r
1002 for (int i = 0; i < (int)channels.size(); ++i)
\r
1003 swizzle->addImmediateOperand(channels[i]);
\r
1004 buildPoint->addInstruction(swizzle);
\r
1006 return swizzle->getResultId();
\r
1009 // Comments in header
\r
1010 Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)
\r
1012 assert(getNumComponents(source) == channels.size());
\r
1013 if (channels.size() == 1 && getNumComponents(source) == 1)
\r
1014 return createCompositeInsert(source, target, typeId, channels.front());
\r
1016 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
\r
1017 swizzle->addIdOperand(target);
\r
1018 swizzle->addIdOperand(source);
\r
1020 // Set up an identity shuffle from the base value to the result value
\r
1021 unsigned int components[4];
\r
1022 int numTargetComponents = getNumComponents(target);
\r
1023 for (int i = 0; i < numTargetComponents; ++i)
\r
1024 components[i] = i;
\r
1026 // Punch in the l-value swizzle
\r
1027 for (int i = 0; i < (int)channels.size(); ++i)
\r
1028 components[channels[i]] = numTargetComponents + i;
\r
1030 // finish the instruction with these components selectors
\r
1031 for (int i = 0; i < numTargetComponents; ++i)
\r
1032 swizzle->addImmediateOperand(components[i]);
\r
1033 buildPoint->addInstruction(swizzle);
\r
1035 return swizzle->getResultId();
\r
1038 // Comments in header
\r
1039 void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
\r
1041 int direction = getNumComponents(right) - getNumComponents(left);
\r
1043 if (direction > 0)
\r
1044 left = smearScalar(precision, left, getTypeId(right));
\r
1045 else if (direction < 0)
\r
1046 right = smearScalar(precision, right, getTypeId(left));
\r
1051 // Comments in header
\r
1052 Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)
\r
1054 assert(getNumComponents(scalar) == 1);
\r
1056 int numComponents = getNumTypeComponents(vectorType);
\r
1057 if (numComponents == 1)
\r
1060 Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
\r
1061 for (int c = 0; c < numComponents; ++c)
\r
1062 smear->addIdOperand(scalar);
\r
1063 buildPoint->addInstruction(smear);
\r
1065 return smear->getResultId();
\r
1068 // Comments in header
\r
1069 Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
\r
1071 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
\r
1072 inst->addIdOperand(builtins);
\r
1073 inst->addImmediateOperand(entryPoint);
\r
1074 for (int arg = 0; arg < (int)args.size(); ++arg)
\r
1075 inst->addIdOperand(args[arg]);
\r
1077 buildPoint->addInstruction(inst);
\r
1078 return inst->getResultId();
\r
1081 // Accept all parameters needed to create a texture instruction.
\r
1082 // Create the correct instruction based on the inputs, and make the call.
\r
1083 Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters& parameters)
\r
1085 static const int maxTextureArgs = 5;
\r
1086 Id texArgs[maxTextureArgs] = {};
\r
1089 // Set up the arguments
\r
1093 texArgs[numArgs++] = parameters.sampler;
\r
1094 texArgs[numArgs++] = parameters.coords;
\r
1096 if (parameters.gradX) {
\r
1097 texArgs[numArgs++] = parameters.gradX;
\r
1098 texArgs[numArgs++] = parameters.gradY;
\r
1100 if (parameters.lod)
\r
1101 texArgs[numArgs++] = parameters.lod;
\r
1102 if (parameters.offset)
\r
1103 texArgs[numArgs++] = parameters.offset;
\r
1104 if (parameters.bias)
\r
1105 texArgs[numArgs++] = parameters.bias;
\r
1106 if (parameters.Dref)
\r
1107 texArgs[numArgs++] = parameters.Dref;
\r
1110 // Set up the instruction
\r
1114 if (proj && parameters.gradX && parameters.offset)
\r
1115 opCode = OpTextureSampleProjGradOffset;
\r
1116 else if (proj && parameters.lod && parameters.offset)
\r
1117 opCode = OpTextureSampleProjLodOffset;
\r
1118 else if (parameters.gradX && parameters.offset)
\r
1119 opCode = OpTextureSampleGradOffset;
\r
1120 else if (proj && parameters.offset)
\r
1121 opCode = OpTextureSampleProjOffset;
\r
1122 else if (parameters.lod && parameters.offset)
\r
1123 opCode = OpTextureSampleLodOffset;
\r
1124 else if (proj && parameters.gradX)
\r
1125 opCode = OpTextureSampleProjGrad;
\r
1126 else if (proj && parameters.lod)
\r
1127 opCode = OpTextureSampleProjLod;
\r
1128 else if (parameters.offset)
\r
1129 opCode = OpTextureSampleOffset;
\r
1130 else if (parameters.gradX)
\r
1131 opCode = OpTextureSampleGrad;
\r
1133 opCode = OpTextureSampleProj;
\r
1134 else if (parameters.lod)
\r
1135 opCode = OpTextureSampleLod;
\r
1136 else if (parameters.Dref)
\r
1137 opCode = OpTextureSampleDref;
\r
1139 opCode = OpTextureSample;
\r
1141 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
\r
1142 for (int op = 0; op < numArgs; ++op)
\r
1143 textureInst->addIdOperand(texArgs[op]);
\r
1144 setPrecision(textureInst->getResultId(), precision);
\r
1145 buildPoint->addInstruction(textureInst);
\r
1147 return textureInst->getResultId();
\r
1150 // Comments in header
\r
1151 Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)
\r
1153 // Figure out the result type
\r
1156 case OpTextureQuerySize:
\r
1157 case OpTextureQuerySizeLod:
\r
1159 int numComponents;
\r
1160 switch (getDimensionality(parameters.sampler)) {
\r
1163 numComponents = 1;
\r
1168 numComponents = 2;
\r
1171 numComponents = 3;
\r
1174 MissingFunctionality("texture query dimensionality");
\r
1177 if (isArrayedSampler(parameters.sampler))
\r
1179 if (numComponents == 1)
\r
1180 resultType = makeIntType(32);
\r
1182 resultType = makeVectorType(makeIntType(32), numComponents);
\r
1186 case OpTextureQueryLod:
\r
1187 resultType = makeVectorType(makeFloatType(32), 2);
\r
1189 case OpTextureQueryLevels:
\r
1190 case OpTextureQuerySamples:
\r
1191 resultType = makeIntType(32);
\r
1194 MissingFunctionality("Texture query op code");
\r
1197 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
\r
1198 query->addIdOperand(parameters.sampler);
\r
1199 if (parameters.coords)
\r
1200 query->addIdOperand(parameters.coords);
\r
1201 if (parameters.lod)
\r
1202 query->addIdOperand(parameters.lod);
\r
1203 buildPoint->addInstruction(query);
\r
1205 return query->getResultId();
\r
1208 // Comments in header
\r
1209 //Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)
\r
1211 // // Return type is only flexible type
\r
1212 // Function* opCode = (fSamplePosition, returnType);
\r
1214 // Instruction* instr = (opCode, sampleIdx);
\r
1215 // setPrecision(instr, precision);
\r
1220 // Comments in header
\r
1221 //Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)
\r
1223 // Op opCode = isSigned ? sBitFieldExtract
\r
1224 // : uBitFieldExtract;
\r
1226 // if (isScalar(offset) == false || isScalar(bits) == false)
\r
1227 // MissingFunctionality("bitFieldExtract operand types");
\r
1229 // // Dest and value are matching flexible types
\r
1230 // Function* opCode = (opCode, id->getType(), id->getType());
\r
1232 // assert(opCode);
\r
1234 // Instruction* instr = (opCode, id, offset, bits);
\r
1235 // setPrecision(instr, precision);
\r
1240 // Comments in header
\r
1241 //Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)
\r
1243 // Op opCode = bitFieldInsert;
\r
1245 // if (isScalar(offset) == false || isScalar(bits) == false)
\r
1246 // MissingFunctionality("bitFieldInsert operand types");
\r
1248 // // Dest, base, and insert are matching flexible types
\r
1249 // Function* opCode = (opCode, base->getType(), base->getType(), base->getType());
\r
1251 // assert(opCode);
\r
1253 // Instruction* instr = (opCode, base, insert, offset, bits);
\r
1254 // setPrecision(instr, precision);
\r
1259 // Comments in header
\r
1260 Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)
\r
1262 Id boolType = makeBoolType();
\r
1263 Id valueType = getTypeId(value1);
\r
1265 assert(valueType == getTypeId(value2));
\r
1266 assert(! isScalar(value1));
\r
1270 if (isVectorType(valueType)) {
\r
1271 Id boolVectorType = makeVectorType(boolType, getNumTypeComponents(valueType));
\r
1274 if (getMostBasicTypeClass(valueType) == OpTypeFloat)
\r
1275 op = equal ? OpFOrdEqual : OpFOrdNotEqual;
\r
1277 op = equal ? OpIEqual : OpINotEqual;
\r
1279 boolVector = createBinOp(op, boolVectorType, value1, value2);
\r
1280 setPrecision(boolVector, precision);
\r
1282 // Reduce vector compares with any() and all().
\r
1284 op = equal ? OpAll : OpAny;
\r
1286 return createUnaryOp(op, boolType, boolVector);
\r
1289 spv::MissingFunctionality("Composite comparison of non-vectors");
\r
1293 // Recursively handle aggregates, which include matrices, arrays, and structures
\r
1294 // and accumulate the results.
\r
1300 //int numElements;
\r
1301 //const llvm::ArrayType* arrayType = llvm::dyn_cast<llvm::ArrayType>(value1->getType());
\r
1303 // numElements = (int)arrayType->getNumElements();
\r
1305 // // better be structure
\r
1306 // const llvm::StructType* structType = llvm::dyn_cast<llvm::StructType>(value1->getType());
\r
1307 // assert(structType);
\r
1308 // numElements = structType->getNumElements();
\r
1311 //assert(numElements > 0);
\r
1313 //for (int element = 0; element < numElements; ++element) {
\r
1314 // // Get intermediate comparison values
\r
1315 // llvm::Value* element1 = builder.CreateExtractValue(value1, element, "element1");
\r
1316 // setInstructionPrecision(element1, precision);
\r
1317 // llvm::Value* element2 = builder.CreateExtractValue(value2, element, "element2");
\r
1318 // setInstructionPrecision(element2, precision);
\r
1320 // llvm::Value* subResult = createCompare(precision, element1, element2, equal, "comp");
\r
1322 // // Accumulate intermediate comparison
\r
1323 // if (element == 0)
\r
1324 // result = subResult;
\r
1327 // result = builder.CreateAnd(result, subResult);
\r
1329 // result = builder.CreateOr(result, subResult);
\r
1330 // setInstructionPrecision(result, precision);
\r
1337 // Comments in header
\r
1338 //Id Builder::createOperation(Decoration precision, Op opCode, Id operand)
\r
1340 // Op* opCode = 0;
\r
1342 // // Handle special return types here. Things that don't have same result type as parameter
\r
1343 // switch (opCode) {
\r
1347 // case fFloatBitsToInt:
\r
1349 // case fIntBitsTofloat:
\r
1351 // case fPackSnorm2x16:
\r
1352 // case fPackUnorm2x16:
\r
1353 // case fPackHalf2x16:
\r
1355 // case fUnpackUnorm2x16:
\r
1356 // case fUnpackSnorm2x16:
\r
1357 // case fUnpackHalf2x16:
\r
1362 // case fPackUnorm4x8:
\r
1363 // case fPackSnorm4x8:
\r
1364 // case fUnpackUnorm4x8:
\r
1365 // case fUnpackSnorm4x8:
\r
1366 // case fPackDouble2x32:
\r
1367 // case fUnpackDouble2x32:
\r
1370 // // scalar result type
\r
1374 // // fixed result type
\r
1377 // // modf() will return a struct that the caller must decode
\r
1380 // // Unary operations that have operand and dest with same flexible type
\r
1384 // assert(opCode);
\r
1386 // Instruction* instr = (opCode, operand);
\r
1387 // setPrecision(instr, precision);
\r
1392 //// Comments in header
\r
1393 //Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)
\r
1395 // Function* opCode = 0;
\r
1397 // // Handle special return types here. Things that don't have same result type as parameter
\r
1398 // switch (opCode) {
\r
1399 // case fDistance:
\r
1403 // // scalar result type
\r
1406 // // first argument can be scalar, return and second argument match
\r
1408 // case fSmoothStep:
\r
1409 // // first argument can be scalar, return and second argument match
\r
1412 // // Binary operations that have operand and dest with same flexible type
\r
1416 // assert(opCode);
\r
1418 // Instruction* instr = (opCode, operand0, operand1);
\r
1419 // setPrecision(instr, precision);
\r
1424 //Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)
\r
1426 // Function* opCode;
\r
1428 // // Handle special return types here. Things that don't have same result type as parameter
\r
1429 // switch (opCode) {
\r
1430 // case fSmoothStep:
\r
1431 // // first argument can be scalar, return and second argument match
\r
1434 // // Use operand0 type as result type
\r
1438 // assert(opCode);
\r
1440 // Instruction* instr = (opCode, operand0, operand1, operand2);
\r
1441 // setPrecision(instr, precision);
\r
1446 // OpCompositeConstruct
\r
1447 Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)
\r
1449 assert(isAggregateType(typeId) || getNumTypeComponents(typeId) > 1 && getNumTypeComponents(typeId) == constituents.size());
\r
1451 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
\r
1452 for (int c = 0; c < (int)constituents.size(); ++c)
\r
1453 op->addIdOperand(constituents[c]);
\r
1454 buildPoint->addInstruction(op);
\r
1456 return op->getResultId();
\r
1459 // Vector or scalar constructor
\r
1460 Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
\r
1463 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
\r
1464 unsigned int targetComponent = 0;
\r
1466 // Special case: when calling a vector constructor with a single scalar
\r
1467 // argument, smear the scalar
\r
1468 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
\r
1469 return smearScalar(precision, sources[0], resultTypeId);
\r
1471 Id scalarTypeId = getScalarTypeId(resultTypeId);
\r
1472 std::vector<Id> constituents; // accumulate the arguments for OpCompositeConstruct
\r
1473 for (unsigned int i = 0; i < sources.size(); ++i) {
\r
1474 if (isAggregate(sources[i]))
\r
1475 MissingFunctionality("aggregate in vector constructor");
\r
1477 unsigned int sourceSize = getNumComponents(sources[i]);
\r
1479 unsigned int sourcesToUse = sourceSize;
\r
1480 if (sourcesToUse + targetComponent > numTargetComponents)
\r
1481 sourcesToUse = numTargetComponents - targetComponent;
\r
1483 for (unsigned int s = 0; s < sourcesToUse; ++s) {
\r
1484 Id arg = sources[i];
\r
1485 if (sourceSize > 1) {
\r
1486 std::vector<unsigned> swiz;
\r
1487 swiz.push_back(s);
\r
1488 arg = createRvalueSwizzle(scalarTypeId, arg, swiz);
\r
1491 if (numTargetComponents > 1)
\r
1492 constituents.push_back(arg);
\r
1495 ++targetComponent;
\r
1498 if (targetComponent >= numTargetComponents)
\r
1502 if (constituents.size() > 0)
\r
1503 result = createCompositeConstruct(resultTypeId, constituents);
\r
1505 setPrecision(result, precision);
\r
1510 // Comments in header
\r
1511 Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
\r
1513 Id componentTypeId = getScalarTypeId(resultTypeId);
\r
1514 int numCols = getTypeNumColumns(resultTypeId);
\r
1515 int numRows = getTypeNumRows(resultTypeId);
\r
1517 // Will use a two step process
\r
1518 // 1. make a compile-time 2D array of values
\r
1519 // 2. construct a matrix from that array
\r
1523 // initialize the array to the identity matrix
\r
1524 Id ids[maxMatrixSize][maxMatrixSize];
\r
1525 Id one = makeFloatConstant(1.0);
\r
1526 Id zero = makeFloatConstant(0.0);
\r
1527 for (int col = 0; col < 4; ++col) {
\r
1528 for (int row = 0; row < 4; ++row) {
\r
1530 ids[col][row] = one;
\r
1532 ids[col][row] = zero;
\r
1536 // modify components as dictated by the arguments
\r
1537 if (sources.size() == 1 && isScalar(sources[0])) {
\r
1538 // a single scalar; resets the diagonals
\r
1539 for (int col = 0; col < 4; ++col)
\r
1540 ids[col][col] = sources[0];
\r
1541 } else if (isMatrix(sources[0])) {
\r
1542 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
\r
1543 Id matrix = sources[0];
\r
1544 int minCols = std::min(numCols, getNumColumns(matrix));
\r
1545 int minRows = std::min(numRows, getNumRows(matrix));
\r
1546 for (int col = 0; col < minCols; ++col) {
\r
1547 std::vector<unsigned> indexes;
\r
1548 indexes.push_back(col);
\r
1549 for (int row = 0; row < minRows; ++row) {
\r
1550 indexes.push_back(row);
\r
1551 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
\r
1552 indexes.pop_back();
\r
1553 setPrecision(ids[col][row], precision);
\r
1557 // fill in the matrix in column-major order with whatever argument components are available
\r
1561 for (int arg = 0; arg < (int)sources.size(); ++arg) {
\r
1562 Id argComp = sources[arg];
\r
1563 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
\r
1564 if (getNumComponents(sources[arg]) > 1) {
\r
1565 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
\r
1566 setPrecision(argComp, precision);
\r
1568 ids[col][row++] = argComp;
\r
1569 if (row == numRows) {
\r
1578 // Step 2: Construct a matrix from that array.
\r
1579 // First make the column vectors, then make the matrix.
\r
1581 // make the column vectors
\r
1582 Id columnTypeId = getContainedTypeId(resultTypeId);
\r
1583 std::vector<Id> matrixColumns;
\r
1584 for (int col = 0; col < numCols; ++col) {
\r
1585 std::vector<Id> vectorComponents;
\r
1586 for (int row = 0; row < numRows; ++row)
\r
1587 vectorComponents.push_back(ids[col][row]);
\r
1588 matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));
\r
1591 // make the matrix
\r
1592 return createCompositeConstruct(resultTypeId, matrixColumns);
\r
1595 // Comments in header
\r
1596 Builder::If::If(Id cond, Builder& gb) :
\r
1601 function = &builder.getBuildPoint()->getParent();
\r
1603 // make the blocks, but only put the then-block into the function,
\r
1604 // the else-block and merge-block will be added later, in order, after
\r
1605 // earlier code is emitted
\r
1606 thenBlock = new Block(builder.getUniqueId(), *function);
\r
1607 mergeBlock = new Block(builder.getUniqueId(), *function);
\r
1609 // Save the current block, so that we can add in the flow control split when
\r
1610 // makeEndIf is called.
\r
1611 headerBlock = builder.getBuildPoint();
\r
1613 function->addBlock(thenBlock);
\r
1614 builder.setBuildPoint(thenBlock);
\r
1617 // Comments in header
\r
1618 void Builder::If::makeBeginElse()
\r
1620 // Close out the "then" by having it jump to the mergeBlock
\r
1621 builder.createBranch(mergeBlock);
\r
1623 // Make the first else block and add it to the function
\r
1624 elseBlock = new Block(builder.getUniqueId(), *function);
\r
1625 function->addBlock(elseBlock);
\r
1627 // Start building the else block
\r
1628 builder.setBuildPoint(elseBlock);
\r
1631 // Comments in header
\r
1632 void Builder::If::makeEndIf()
\r
1634 // jump to the merge block
\r
1635 builder.createBranch(mergeBlock);
\r
1637 // Go back to the headerBlock and make the flow control split
\r
1638 builder.setBuildPoint(headerBlock);
\r
1639 builder.createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
\r
1641 builder.createConditionalBranch(condition, thenBlock, elseBlock);
\r
1643 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
\r
1645 // add the merge block to the function
\r
1646 function->addBlock(mergeBlock);
\r
1647 builder.setBuildPoint(mergeBlock);
\r
1650 // Comments in header
\r
1651 void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,
\r
1652 std::vector<Block*>& segmentBlocks)
\r
1654 Function& function = buildPoint->getParent();
\r
1656 // make all the blocks
\r
1657 for (int s = 0; s < numSegments; ++s)
\r
1658 segmentBlocks.push_back(new Block(getUniqueId(), function));
\r
1660 Block* mergeBlock = new Block(getUniqueId(), function);
\r
1662 // make and insert the switch's selection-merge instruction
\r
1663 createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
\r
1665 // make the switch instruction
\r
1666 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
\r
1667 switchInst->addIdOperand(selector);
\r
1668 switchInst->addIdOperand(defaultSegment >= 0 ? segmentBlocks[defaultSegment]->getId() : mergeBlock->getId());
\r
1669 for (int i = 0; i < (int)caseValues.size(); ++i) {
\r
1670 switchInst->addImmediateOperand(caseValues[i]);
\r
1671 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
\r
1673 buildPoint->addInstruction(switchInst);
\r
1675 // push the merge block
\r
1676 switchMerges.push(mergeBlock);
\r
1679 // Comments in header
\r
1680 void Builder::addSwitchBreak()
\r
1682 // branch to the top of the merge block stack
\r
1683 createBranch(switchMerges.top());
\r
1684 createAndSetNoPredecessorBlock("post-switch-break");
\r
1687 // Comments in header
\r
1688 void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
\r
1690 int lastSegment = nextSegment - 1;
\r
1691 if (lastSegment >= 0) {
\r
1692 // Close out previous segment by jumping, if necessary, to next segment
\r
1693 if (! buildPoint->isTerminated())
\r
1694 createBranch(segmentBlock[nextSegment]);
\r
1696 Block* block = segmentBlock[nextSegment];
\r
1697 block->getParent().addBlock(block);
\r
1698 setBuildPoint(block);
\r
1701 // Comments in header
\r
1702 void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
\r
1704 // Close out previous segment by jumping, if necessary, to next segment
\r
1705 if (! buildPoint->isTerminated())
\r
1708 switchMerges.top()->getParent().addBlock(switchMerges.top());
\r
1709 setBuildPoint(switchMerges.top());
\r
1711 switchMerges.pop();
\r
1714 // Comments in header
\r
1715 void Builder::makeNewLoop()
\r
1719 loop.function = &getBuildPoint()->getParent();
\r
1720 loop.header = new Block(getUniqueId(), *loop.function);
\r
1721 loop.merge = new Block(getUniqueId(), *loop.function);
\r
1725 // Branch into the loop
\r
1726 createBranch(loop.header);
\r
1728 // Set ourselves inside the loop
\r
1729 loop.function->addBlock(loop.header);
\r
1730 setBuildPoint(loop.header);
\r
1733 void Builder::createLoopHeaderBranch(Id condition)
\r
1735 Loop loop = loops.top();
\r
1737 Block* body = new Block(getUniqueId(), *loop.function);
\r
1738 createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
\r
1739 createConditionalBranch(condition, body, loop.merge);
\r
1740 loop.function->addBlock(body);
\r
1741 setBuildPoint(body);
\r
1744 // Add a back-edge (e.g "continue") for the innermost loop that you're in
\r
1745 void Builder::createLoopBackEdge(bool implicit)
\r
1747 Loop loop = loops.top();
\r
1749 // Just branch back, and set up a block for dead code if it's a user continue
\r
1750 createBranch(loop.header);
\r
1752 createAndSetNoPredecessorBlock("post-loop-continue");
\r
1755 // Add an exit (e.g. "break") for the innermost loop that you're in
\r
1756 void Builder::createLoopExit()
\r
1758 createBranch(loops.top().merge);
\r
1759 createAndSetNoPredecessorBlock("post-loop-break");
\r
1762 // Close the innermost loop
\r
1763 void Builder::closeLoop()
\r
1765 // Branch back to the top
\r
1766 createLoopBackEdge(true);
\r
1768 // Add the merge block and set the build point to it
\r
1769 Loop loop = loops.top();
\r
1770 loop.function->addBlock(loop.merge);
\r
1771 setBuildPoint(loop.merge);
\r
1776 void Builder::clearAccessChain()
\r
1778 accessChain.base = 0;
\r
1779 accessChain.indexChain.clear();
\r
1780 accessChain.instr = 0;
\r
1781 accessChain.swizzle.clear();
\r
1782 accessChain.component = 0;
\r
1783 accessChain.swizzleTargetWidth = 0;
\r
1784 accessChain.resultType = NoType;
\r
1785 accessChain.isRValue = false;
\r
1788 // Comments in header
\r
1789 void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, int width, Id type)
\r
1791 // if needed, propagate the swizzle for the current access chain
\r
1792 if (accessChain.swizzle.size()) {
\r
1793 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
\r
1794 accessChain.swizzle.resize(0);
\r
1795 for (unsigned int i = 0; i < swizzle.size(); ++i) {
\r
1796 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
\r
1799 accessChain.swizzle = swizzle;
\r
1802 // track width the swizzle operates on; once known, it does not change
\r
1803 if (accessChain.swizzleTargetWidth == 0)
\r
1804 accessChain.swizzleTargetWidth = width;
\r
1806 accessChain.resultType = type;
\r
1808 // determine if we need to track this swizzle anymore
\r
1809 simplifyAccessChainSwizzle();
\r
1812 // Comments in header
\r
1813 void Builder::accessChainStore(Id rvalue)
\r
1815 assert(accessChain.isRValue == false);
\r
1817 Id base = collapseAccessChain();
\r
1819 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
\r
1820 // extract and insert elements to perform writeMask and/or swizzle.
\r
1823 if (accessChain.swizzle.size()) {
\r
1824 Id tempBaseId = createLoad(base);
\r
1825 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);
\r
1826 } else if (accessChain.component) {
\r
1827 Instruction* vectorInsert = new Instruction(getUniqueId(), getTypeId(rvalue), OpVectorInsertDynamic);
\r
1828 vectorInsert->addIdOperand(createLoad(base));
\r
1829 vectorInsert->addIdOperand(rvalue);
\r
1830 vectorInsert->addIdOperand(accessChain.component);
\r
1831 buildPoint->addInstruction(vectorInsert);
\r
1833 source = vectorInsert->getResultId();
\r
1837 createStore(source, base);
\r
1840 // Comments in header
\r
1841 Id Builder::accessChainLoad(Decoration /*precision*/)
\r
1845 if (accessChain.isRValue) {
\r
1846 if (accessChain.indexChain.size() > 0) {
\r
1847 // if all the accesses are constants, we can use OpCompositeExtract
\r
1848 std::vector<unsigned> indexes;
\r
1849 bool constant = true;
\r
1850 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
\r
1851 if (isConstantScalar(accessChain.indexChain[i]))
\r
1852 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
\r
1860 id = createCompositeExtract(accessChain.base, accessChain.resultType, indexes);
\r
1862 // make a new function variable for this r-value
\r
1863 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
\r
1866 createStore(accessChain.base, lValue);
\r
1868 // move base to the new variable
\r
1869 accessChain.base = lValue;
\r
1870 accessChain.isRValue = false;
\r
1872 // load through the access chain
\r
1873 id = createLoad(collapseAccessChain());
\r
1876 id = accessChain.base;
\r
1878 // load through the access chain
\r
1879 id = createLoad(collapseAccessChain());
\r
1882 if (accessChain.component) {
\r
1883 Instruction* vectorExtract = new Instruction(getUniqueId(), getScalarTypeId(getTypeId(id)), OpVectorExtractDynamic);
\r
1884 vectorExtract->addIdOperand(id);
\r
1885 vectorExtract->addIdOperand(accessChain.component);
\r
1886 buildPoint->addInstruction(vectorExtract);
\r
1887 id = vectorExtract->getResultId();
\r
1888 } else if (accessChain.swizzle.size())
\r
1889 id = createRvalueSwizzle(accessChain.resultType, id, accessChain.swizzle);
\r
1894 Id Builder::accessChainGetLValue()
\r
1896 assert(accessChain.isRValue == false);
\r
1898 Id lvalue = collapseAccessChain();
\r
1900 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
\r
1901 // extract and insert elements to perform writeMask and/or swizzle. This does not
\r
1902 // go with getting a direct l-value pointer.
\r
1903 assert(accessChain.swizzle.size() == 0);
\r
1904 assert(accessChain.component == spv::NoResult);
\r
1909 void Builder::dump(std::vector<unsigned int>& out) const
\r
1911 // Header, before first instructions:
\r
1912 out.push_back(MagicNumber);
\r
1913 out.push_back(Version);
\r
1914 out.push_back(builderNumber);
\r
1915 out.push_back(uniqueId + 1);
\r
1918 // First instructions, some created on the spot here:
\r
1919 if (source != SourceLanguageUnknown) {
\r
1920 Instruction sourceInst(0, 0, OpSource);
\r
1921 sourceInst.addImmediateOperand(source);
\r
1922 sourceInst.addImmediateOperand(sourceVersion);
\r
1923 sourceInst.dump(out);
\r
1925 for (int e = 0; e < (int)extensions.size(); ++e) {
\r
1926 Instruction extInst(0, 0, OpSourceExtension);
\r
1927 extInst.addStringOperand(extensions[e]);
\r
1928 extInst.dump(out);
\r
1930 // TBD: OpExtension ...
\r
1931 dumpInstructions(out, imports);
\r
1932 Instruction memInst(0, 0, OpMemoryModel);
\r
1933 memInst.addImmediateOperand(addressModel);
\r
1934 memInst.addImmediateOperand(memoryModel);
\r
1935 memInst.dump(out);
\r
1937 // Instructions saved up while building:
\r
1938 dumpInstructions(out, entryPoints);
\r
1939 dumpInstructions(out, executionModes);
\r
1940 dumpInstructions(out, names);
\r
1941 dumpInstructions(out, lines);
\r
1942 dumpInstructions(out, decorations);
\r
1943 dumpInstructions(out, constantsTypesGlobals);
\r
1944 dumpInstructions(out, externals);
\r
1951 // Protected methods.
\r
1954 Id Builder::collapseAccessChain()
\r
1956 // TODO: bring in an individual component swizzle here, so that a pointer
\r
1957 // all the way to the component level can be created.
\r
1958 assert(accessChain.isRValue == false);
\r
1960 if (accessChain.indexChain.size() > 0) {
\r
1961 if (accessChain.instr == 0) {
\r
1962 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
\r
1963 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
\r
1966 return accessChain.instr;
\r
1968 return accessChain.base;
\r
1971 // clear out swizzle if it is redundant
\r
1972 void Builder::simplifyAccessChainSwizzle()
\r
1974 // if swizzle has fewer components than our target, it is a writemask
\r
1975 if (accessChain.swizzleTargetWidth > (int)accessChain.swizzle.size())
\r
1978 // if components are out of order, it is a swizzle
\r
1979 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
\r
1980 if (i != accessChain.swizzle[i])
\r
1984 // otherwise, there is no need to track this swizzle
\r
1985 accessChain.swizzle.clear();
\r
1986 accessChain.swizzleTargetWidth = 0;
\r
1989 // Utility method for creating a new block and setting the insert point to
\r
1990 // be in it. This is useful for flow-control operations that need a "dummy"
\r
1991 // block proceeding them (e.g. instructions after a discard, etc).
\r
1992 void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
\r
1994 Block* block = new Block(getUniqueId(), buildPoint->getParent());
\r
1995 block->setUnreachable();
\r
1996 buildPoint->getParent().addBlock(block);
\r
1997 setBuildPoint(block);
\r
2000 // addName(block->getId(), name);
\r
2003 // Comments in header
\r
2004 void Builder::createBranch(Block* block)
\r
2006 Instruction* branch = new Instruction(OpBranch);
\r
2007 branch->addIdOperand(block->getId());
\r
2008 buildPoint->addInstruction(branch);
\r
2009 block->addPredecessor(buildPoint);
\r
2012 void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)
\r
2014 Instruction* merge = new Instruction(mergeCode);
\r
2015 merge->addIdOperand(mergeBlock->getId());
\r
2016 merge->addImmediateOperand(control);
\r
2017 buildPoint->addInstruction(merge);
\r
2020 void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
\r
2022 Instruction* branch = new Instruction(OpBranchConditional);
\r
2023 branch->addIdOperand(condition);
\r
2024 branch->addIdOperand(thenBlock->getId());
\r
2025 branch->addIdOperand(elseBlock->getId());
\r
2026 buildPoint->addInstruction(branch);
\r
2027 thenBlock->addPredecessor(buildPoint);
\r
2028 elseBlock->addPredecessor(buildPoint);
\r
2031 void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<Instruction*>& instructions) const
\r
2033 for (int i = 0; i < (int)instructions.size(); ++i) {
\r
2034 instructions[i]->dump(out);
\r
2038 void MissingFunctionality(const char* fun)
\r
2040 printf("Missing functionality: %s\n", fun);
\r
2044 void ValidationError(const char* error)
\r
2046 printf("Validation Error: %s\n", error);
\r
2049 }; // end spv namespace
\r