glslang: Fix over 100 warnings from MSVC warning level 4.
[platform/upstream/glslang.git] / SPIRV / SpvBuilder.cpp
1 //\r
2 //Copyright (C) 2014 LunarG, Inc.\r
3 //\r
4 //All rights reserved.\r
5 //\r
6 //Redistribution and use in source and binary forms, with or without\r
7 //modification, are permitted provided that the following conditions\r
8 //are met:\r
9 //\r
10 //    Redistributions of source code must retain the above copyright\r
11 //    notice, this list of conditions and the following disclaimer.\r
12 //\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
17 //\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
21 //\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
34 \r
35 //\r
36 // Author: John Kessenich, LunarG\r
37 //\r
38 \r
39 //\r
40 // Helper for making SPIR-V IR.  Generally, this is documented in the header\r
41 // SpvBuilder.h.\r
42 //\r
43 \r
44 #include <assert.h>\r
45 #include <stdio.h>\r
46 #include <stdlib.h>\r
47 \r
48 #include "SpvBuilder.h"\r
49 \r
50 #ifndef _WIN32\r
51     #include <cstdio>\r
52 #endif\r
53 \r
54 namespace spv {\r
55 \r
56 const int SpvBuilderMagic = 0xBB;\r
57 \r
58 Builder::Builder(unsigned int userNumber) :\r
59     source(SourceLanguageUnknown),\r
60     sourceVersion(0),\r
61     addressModel(AddressingModelLogical),\r
62     memoryModel(MemoryModelGLSL450),\r
63     builderNumber(userNumber << 16 | SpvBuilderMagic),\r
64     buildPoint(0),\r
65     uniqueId(0),\r
66     mainFunction(0),\r
67     stageExit(0)\r
68 {\r
69     clearAccessChain();\r
70 }\r
71 \r
72 Builder::~Builder()\r
73 {\r
74 }\r
75 \r
76 Id Builder::import(const char* name)\r
77 {\r
78     Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);\r
79     import->addStringOperand(name);\r
80     \r
81     imports.push_back(import);\r
82     return import->getResultId();\r
83 }\r
84 \r
85 // For creating new groupedTypes (will return old type if the requested one was already made).\r
86 Id Builder::makeVoidType()\r
87 {\r
88     Instruction* type;\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
94     } else\r
95         type = groupedTypes[OpTypeVoid].back();\r
96 \r
97     return type->getResultId();\r
98 }\r
99 \r
100 Id Builder::makeBoolType()\r
101 {\r
102     Instruction* type;\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
108     } else\r
109         type = groupedTypes[OpTypeBool].back();\r
110 \r
111     return type->getResultId();\r
112 }\r
113 \r
114 Id Builder::makePointer(StorageClass storageClass, Id pointee)\r
115 {\r
116     // try to find it\r
117     Instruction* type;\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
123     }\r
124 \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
132 \r
133     return type->getResultId();\r
134 }\r
135 \r
136 Id Builder::makeIntegerType(int width, bool hasSign)\r
137 {\r
138     // try to find it\r
139     Instruction* type;\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
145     }\r
146 \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
154 \r
155     return type->getResultId();\r
156 }\r
157 \r
158 Id Builder::makeFloatType(int width)\r
159 {\r
160     // try to find it\r
161     Instruction* type;\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
166     }\r
167 \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
174 \r
175     return type->getResultId();\r
176 }\r
177 \r
178 Id Builder::makeStructType(std::vector<Id>& members, const char* name)\r
179 {\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
188 \r
189     return type->getResultId();\r
190 }\r
191 \r
192 Id Builder::makeVectorType(Id component, int size)\r
193 {\r
194     // try to find it\r
195     Instruction* type;\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
201     }\r
202 \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
210 \r
211     return type->getResultId();\r
212 }\r
213 \r
214 Id Builder::makeMatrixType(Id component, int cols, int rows)\r
215 {\r
216     assert(cols <= maxMatrixSize && rows <= maxMatrixSize);\r
217 \r
218     Id column = makeVectorType(component, rows);\r
219 \r
220     // try to find it\r
221     Instruction* type;\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
227     }\r
228 \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
236 \r
237     return type->getResultId();\r
238 }\r
239 \r
240 Id Builder::makeArrayType(Id element, unsigned size)\r
241 {\r
242     // First, we need a constant instruction for the size\r
243     Id sizeId = makeUintConstant(size);\r
244 \r
245     // try to find existing type\r
246     Instruction* 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
252     }\r
253 \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
261 \r
262     return type->getResultId();\r
263 }\r
264 \r
265 Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)\r
266 {\r
267     // try to find it\r
268     Instruction* type;\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
272             continue;\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
276                 mismatch = true;\r
277                 break;\r
278             }\r
279         }\r
280         if (! mismatch)\r
281             return type->getResultId();            \r
282     }\r
283 \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
292 \r
293     return type->getResultId();\r
294 }\r
295 \r
296 Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)\r
297 {\r
298     // try to find it\r
299     Instruction* type;\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
309     }\r
310 \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
319 \r
320     groupedTypes[OpTypeSampler].push_back(type);\r
321     constantsTypesGlobals.push_back(type);\r
322     module.mapInstruction(type);\r
323 \r
324     return type->getResultId();\r
325 }\r
326 \r
327 Id Builder::getDerefTypeId(Id resultId) const\r
328 {\r
329     Id typeId = getTypeId(resultId);\r
330     assert(isPointerType(typeId));\r
331 \r
332     return module.getInstruction(typeId)->getImmediateOperand(1);\r
333 }\r
334 \r
335 Op Builder::getMostBasicTypeClass(Id typeId) const\r
336 {\r
337     Instruction* instr = module.getInstruction(typeId);\r
338 \r
339     Op typeClass = instr->getOpCode();\r
340     switch (typeClass)\r
341     {\r
342     case OpTypeVoid:\r
343     case OpTypeBool:\r
344     case OpTypeInt:\r
345     case OpTypeFloat:\r
346     case OpTypeStruct:\r
347         return typeClass;\r
348     case OpTypeVector:\r
349     case OpTypeMatrix:\r
350     case OpTypeArray:\r
351     case OpTypeRuntimeArray:\r
352         return getMostBasicTypeClass(instr->getIdOperand(0));\r
353     case OpTypePointer:\r
354         return getMostBasicTypeClass(instr->getIdOperand(1));\r
355     default:\r
356         MissingFunctionality("getMostBasicTypeClass");\r
357         return OpTypeFloat;\r
358     }\r
359 }\r
360 \r
361 int Builder::getNumTypeComponents(Id typeId) const\r
362 {\r
363     Instruction* instr = module.getInstruction(typeId);\r
364 \r
365     switch (instr->getOpCode())\r
366     {\r
367     case OpTypeBool:\r
368     case OpTypeInt:\r
369     case OpTypeFloat:\r
370         return 1;\r
371     case OpTypeVector:\r
372     case OpTypeMatrix:\r
373         return instr->getImmediateOperand(1);\r
374     default:\r
375         MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");\r
376         return 1;\r
377     }\r
378 }\r
379 \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
384 {\r
385     Instruction* instr = module.getInstruction(typeId);\r
386 \r
387     Op typeClass = instr->getOpCode();\r
388     switch (typeClass)\r
389     {\r
390     case OpTypeVoid:\r
391     case OpTypeBool:\r
392     case OpTypeInt:\r
393     case OpTypeFloat:\r
394     case OpTypeStruct:\r
395         return instr->getResultId();\r
396     case OpTypeVector:\r
397     case OpTypeMatrix:\r
398     case OpTypeArray:\r
399     case OpTypeRuntimeArray:\r
400     case OpTypePointer:\r
401         return getScalarTypeId(getContainedTypeId(typeId));\r
402     default:\r
403         MissingFunctionality("getScalarTypeId");\r
404         return NoResult;\r
405     }\r
406 }\r
407 \r
408 // Return the type of 'member' of a composite.\r
409 Id Builder::getContainedTypeId(Id typeId, int member) const\r
410 {\r
411     Instruction* instr = module.getInstruction(typeId);\r
412 \r
413     Op typeClass = instr->getOpCode();\r
414     switch (typeClass)\r
415     {\r
416     case OpTypeVector:\r
417     case OpTypeMatrix:\r
418     case OpTypeArray:\r
419     case OpTypeRuntimeArray:\r
420         return instr->getIdOperand(0);\r
421     case OpTypePointer:\r
422         return instr->getIdOperand(1);\r
423     case OpTypeStruct:\r
424         return instr->getIdOperand(member);\r
425     default:\r
426         MissingFunctionality("getContainedTypeId");\r
427         return NoResult;\r
428     }\r
429 }\r
430 \r
431 // Return the immediately contained type of a given composite type.\r
432 Id Builder::getContainedTypeId(Id typeId) const\r
433 {\r
434     return getContainedTypeId(typeId, 0);\r
435 }\r
436 \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
440 {\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
448     }\r
449 \r
450     return 0;\r
451 }\r
452 \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
455 {\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
464     }\r
465 \r
466     return 0;\r
467 }\r
468 \r
469 Id Builder::makeBoolConstant(bool b)\r
470 {\r
471     Id typeId = makeBoolType();\r
472     Instruction* constant;\r
473 \r
474     // See if we already made it\r
475     Id existing = 0;\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
482     }\r
483 \r
484     if (existing)\r
485         return existing;\r
486 \r
487     // Make it\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
492 \r
493     return c->getResultId();\r
494 }\r
495 \r
496 Id Builder::makeIntConstant(Id typeId, unsigned value)\r
497 {\r
498     Id existing = findScalarConstant(OpTypeInt, typeId, value);\r
499     if (existing)\r
500         return existing;\r
501 \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
507 \r
508     return c->getResultId();\r
509 }\r
510 \r
511 Id Builder::makeFloatConstant(float f)\r
512 {\r
513     Id typeId = makeFloatType(32);\r
514     unsigned value = *(unsigned int*)&f;\r
515     Id existing = findScalarConstant(OpTypeFloat, typeId, value);\r
516     if (existing)\r
517         return existing;\r
518 \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
524 \r
525     return c->getResultId();\r
526 }\r
527 \r
528 Id Builder::makeDoubleConstant(double d)\r
529 {\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
535     if (existing)\r
536         return existing;\r
537 \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
544 \r
545     return c->getResultId();\r
546 }\r
547 \r
548 Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const\r
549 {\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
554 \r
555         // same shape?\r
556         if (constant->getNumOperands() != (int)comps.size())\r
557             continue;\r
558 \r
559         // same contents?\r
560         bool mismatch = false;\r
561         for (int op = 0; op < constant->getNumOperands(); ++op) {\r
562             if (constant->getIdOperand(op) != comps[op]) {\r
563                 mismatch = true;\r
564                 break;\r
565             }\r
566         }\r
567         if (! mismatch) {\r
568             found = true;\r
569             break;\r
570         }\r
571     }\r
572 \r
573     return found ? constant->getResultId() : NoResult;\r
574 }\r
575 \r
576 // Comments in header\r
577 Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)\r
578 {\r
579     assert(typeId);\r
580     Op typeClass = getTypeClass(typeId);\r
581 \r
582     switch (typeClass) {\r
583     case OpTypeVector:\r
584     case OpTypeArray:\r
585     case OpTypeStruct:\r
586     case OpTypeMatrix:\r
587         break;\r
588     default:\r
589         MissingFunctionality("Constant composite type in Builder");\r
590         return makeFloatConstant(0.0);\r
591     }\r
592 \r
593     Id existing = findCompositeConstant(typeClass, members);\r
594     if (existing)\r
595         return existing;\r
596 \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
603 \r
604     return c->getResultId();\r
605 }\r
606 \r
607 void Builder::addEntryPoint(ExecutionModel model, Function* function)\r
608 {\r
609     Instruction* entryPoint = new Instruction(OpEntryPoint);\r
610     entryPoint->addImmediateOperand(model);\r
611     entryPoint->addIdOperand(function->getId());\r
612 \r
613     entryPoints.push_back(entryPoint);\r
614 }\r
615 \r
616 void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value)\r
617 {\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
622     if (value >= 0)\r
623         instr->addImmediateOperand(value);\r
624 \r
625     executionModes.push_back(instr);\r
626 }\r
627 \r
628 void Builder::addName(Id id, const char* string)\r
629 {\r
630     Instruction* name = new Instruction(OpName);\r
631     name->addIdOperand(id);\r
632     name->addStringOperand(string);\r
633 \r
634     names.push_back(name);\r
635 }\r
636 \r
637 void Builder::addMemberName(Id id, int memberNumber, const char* string)\r
638 {\r
639     Instruction* name = new Instruction(OpMemberName);\r
640     name->addIdOperand(id);\r
641     name->addImmediateOperand(memberNumber);\r
642     name->addStringOperand(string);\r
643 \r
644     names.push_back(name);\r
645 }\r
646 \r
647 void Builder::addLine(Id target, Id fileName, int lineNum, int column)\r
648 {\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
654 \r
655     lines.push_back(line);\r
656 }\r
657 \r
658 void Builder::addDecoration(Id id, Decoration decoration, int num)\r
659 {\r
660     Instruction* dec = new Instruction(OpDecorate);\r
661     dec->addIdOperand(id);\r
662     dec->addImmediateOperand(decoration);\r
663     if (num >= 0)\r
664         dec->addImmediateOperand(num);\r
665 \r
666     decorations.push_back(dec);\r
667 }\r
668 \r
669 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)\r
670 {\r
671     Instruction* dec = new Instruction(OpMemberDecorate);\r
672     dec->addIdOperand(id);\r
673     dec->addImmediateOperand(member);\r
674     dec->addImmediateOperand(decoration);\r
675     if (num >= 0)\r
676         dec->addImmediateOperand(num);\r
677 \r
678     decorations.push_back(dec);\r
679 }\r
680 \r
681 // Comments in header\r
682 Function* Builder::makeMain()\r
683 {\r
684     assert(! mainFunction);\r
685 \r
686     Block* entry;\r
687     std::vector<Id> params;\r
688 \r
689     mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);\r
690     stageExit = new Block(getUniqueId(), *mainFunction);\r
691 \r
692     return mainFunction;\r
693 }\r
694 \r
695 // Comments in header\r
696 void Builder::closeMain()\r
697 {\r
698     setBuildPoint(stageExit);\r
699     stageExit->addInstruction(new Instruction(NoResult, NoType, OpReturn));\r
700     mainFunction->addBlock(stageExit);\r
701 }\r
702 \r
703 // Comments in header\r
704 Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)\r
705 {\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
709 \r
710     if (entry) {\r
711         *entry = new Block(getUniqueId(), *function);\r
712         function->addBlock(*entry);\r
713         setBuildPoint(*entry);\r
714     }\r
715 \r
716     if (name)\r
717         addName(function->getId(), name);\r
718 \r
719     return function;\r
720 }\r
721 \r
722 // Comments in header\r
723 void Builder::makeReturn(bool implicit, Id retVal, bool isMain)\r
724 {\r
725     if (isMain && retVal)\r
726         MissingFunctionality("return value from main()");\r
727 \r
728     if (isMain)\r
729         createBranch(stageExit);\r
730     else if (retVal) {\r
731         Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);\r
732         inst->addIdOperand(retVal);\r
733         buildPoint->addInstruction(inst);\r
734     } else\r
735         buildPoint->addInstruction(new Instruction(NoResult, NoType, OpReturn));\r
736 \r
737     if (! implicit)\r
738         createAndSetNoPredecessorBlock("post-return");\r
739 }\r
740 \r
741 // Comments in header\r
742 void Builder::leaveFunction(bool main)\r
743 {\r
744     Block* block = buildPoint;\r
745     Function& function = buildPoint->getParent();\r
746     assert(block);\r
747 \r
748     // If our function did not contain a return, add a return void now.\r
749     if (! block->isTerminated()) {\r
750 \r
751         // Whether we're in an unreachable (non-entry) block.\r
752         bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;\r
753 \r
754         if (unreachable) {\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
758         } else if (main)\r
759             makeMainReturn(true);\r
760         else {\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
766                 makeReturn(true);\r
767             else {\r
768                 Id retStorage = createVariable(StorageClassFunction, function.getReturnType(), "dummyReturn");\r
769                 Id retValue = createLoad(retStorage);\r
770                 makeReturn(true, retValue);\r
771             }\r
772         }\r
773     }\r
774 \r
775     if (main)\r
776         closeMain();\r
777 }\r
778 \r
779 // Comments in header\r
780 void Builder::makeDiscard()\r
781 {\r
782     buildPoint->addInstruction(new Instruction(OpKill));\r
783     createAndSetNoPredecessorBlock("post-discard");\r
784 }\r
785 \r
786 // Comments in header\r
787 Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)\r
788 {\r
789     Id pointerType = makePointer(storageClass, type);\r
790     Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);\r
791     inst->addImmediateOperand(storageClass);\r
792 \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
803         break;\r
804 \r
805     case StorageClassFunction:\r
806         // Validation rules require the declaration in the entry block\r
807         buildPoint->getParent().addLocalVariable(inst);\r
808         break;\r
809 \r
810     default:\r
811         MissingFunctionality("storage class in createVariable");\r
812         break;\r
813     }\r
814 \r
815     if (name)\r
816         addName(inst->getResultId(), name);\r
817 \r
818     return inst->getResultId();\r
819 }\r
820 \r
821 // Comments in header\r
822 void Builder::createStore(Id rValue, Id lValue)\r
823 {\r
824     Instruction* store = new Instruction(OpStore);\r
825     store->addIdOperand(lValue);\r
826     store->addIdOperand(rValue);\r
827     buildPoint->addInstruction(store);\r
828 }\r
829 \r
830 // Comments in header\r
831 Id Builder::createLoad(Id lValue)\r
832 {\r
833     Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);\r
834     load->addIdOperand(lValue);\r
835     buildPoint->addInstruction(load);\r
836 \r
837     return load->getResultId();\r
838 }\r
839 \r
840 // Comments in header\r
841 Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)\r
842 {\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
851         } else\r
852             typeId = getContainedTypeId(typeId, offsets[i]);\r
853     }\r
854     typeId = makePointer(storageClass, typeId);\r
855 \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
862 \r
863     return chain->getResultId();\r
864 }\r
865 \r
866 Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)\r
867 {\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
872 \r
873     return extract->getResultId();\r
874 }\r
875 \r
876 Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)\r
877 {\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
883 \r
884     return extract->getResultId();\r
885 }\r
886 \r
887 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)\r
888 {\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
894 \r
895     return insert->getResultId();\r
896 }\r
897 \r
898 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)\r
899 {\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
906 \r
907     return insert->getResultId();\r
908 }\r
909 \r
910 // An opcode that has no operands, no result id, and no type\r
911 void Builder::createNoResultOp(Op opCode)\r
912 {\r
913     Instruction* op = new Instruction(opCode);\r
914     buildPoint->addInstruction(op);\r
915 }\r
916 \r
917 // An opcode that has one operand, no result id, and no type\r
918 void Builder::createNoResultOp(Op opCode, Id operand)\r
919 {\r
920     Instruction* op = new Instruction(opCode);\r
921     op->addIdOperand(operand);\r
922     buildPoint->addInstruction(op);\r
923 }\r
924 \r
925 void Builder::createControlBarrier(unsigned executionScope)\r
926 {\r
927     Instruction* op = new Instruction(OpControlBarrier);\r
928     op->addImmediateOperand(executionScope);\r
929     buildPoint->addInstruction(op);\r
930 }\r
931 \r
932 void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)\r
933 {\r
934     Instruction* op = new Instruction(OpMemoryBarrier);\r
935     op->addImmediateOperand(executionScope);\r
936     op->addImmediateOperand(memorySemantics);\r
937     buildPoint->addInstruction(op);\r
938 }\r
939 \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
942 {\r
943     Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
944     op->addIdOperand(operand);\r
945     buildPoint->addInstruction(op);\r
946 \r
947     return op->getResultId();\r
948 }\r
949 \r
950 Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)\r
951 {\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
956 \r
957     return op->getResultId();\r
958 }\r
959 \r
960 Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)\r
961 {\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
967 \r
968     return op->getResultId();\r
969 }\r
970 \r
971 Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)\r
972 {\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
978 \r
979     return op->getResultId();\r
980 }\r
981 \r
982 Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)\r
983 {\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
989 \r
990     return op->getResultId();\r
991 }\r
992 \r
993 // Comments in header\r
994 Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)\r
995 {\r
996     if (channels.size() == 1)\r
997         return createCompositeExtract(source, typeId, channels.front());\r
998 \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
1005 \r
1006     return swizzle->getResultId();\r
1007 }\r
1008 \r
1009 // Comments in header\r
1010 Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)\r
1011 {\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
1015 \r
1016     Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);\r
1017     swizzle->addIdOperand(target);\r
1018     swizzle->addIdOperand(source);\r
1019 \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
1025 \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
1029 \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
1034 \r
1035     return swizzle->getResultId();\r
1036 }\r
1037 \r
1038 // Comments in header\r
1039 void Builder::promoteScalar(Decoration precision, Id& left, Id& right)\r
1040 {\r
1041     int direction = getNumComponents(right) - getNumComponents(left);\r
1042 \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
1047 \r
1048     return;\r
1049 }\r
1050 \r
1051 // Comments in header\r
1052 Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)\r
1053 {\r
1054     assert(getNumComponents(scalar) == 1);\r
1055 \r
1056     int numComponents = getNumTypeComponents(vectorType);\r
1057     if (numComponents == 1)\r
1058         return scalar;\r
1059 \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
1064 \r
1065     return smear->getResultId();\r
1066 }\r
1067 \r
1068 // Comments in header\r
1069 Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)\r
1070 {\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
1076 \r
1077     buildPoint->addInstruction(inst);\r
1078     return inst->getResultId();\r
1079 }\r
1080 \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
1084 {\r
1085     static const int maxTextureArgs = 5;\r
1086     Id texArgs[maxTextureArgs] = {};\r
1087 \r
1088     //\r
1089     // Set up the arguments\r
1090     //\r
1091 \r
1092     int numArgs = 0;\r
1093     texArgs[numArgs++] = parameters.sampler;\r
1094     texArgs[numArgs++] = parameters.coords;\r
1095 \r
1096     if (parameters.gradX) {\r
1097         texArgs[numArgs++] = parameters.gradX;\r
1098         texArgs[numArgs++] = parameters.gradY;\r
1099     }\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
1108 \r
1109     //\r
1110     // Set up the instruction\r
1111     //\r
1112 \r
1113     Op opCode;\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
1132     else if (proj)\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
1138     else\r
1139         opCode = OpTextureSample;\r
1140 \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
1146 \r
1147     return textureInst->getResultId();\r
1148 }\r
1149 \r
1150 // Comments in header\r
1151 Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)\r
1152 {\r
1153     // Figure out the result type\r
1154     Id resultType;\r
1155     switch (opCode) {\r
1156     case OpTextureQuerySize:\r
1157     case OpTextureQuerySizeLod:\r
1158     {\r
1159         int numComponents;\r
1160         switch (getDimensionality(parameters.sampler)) {\r
1161         case Dim1D:\r
1162         case DimBuffer:\r
1163             numComponents = 1;\r
1164             break;\r
1165         case Dim2D:\r
1166         case DimCube:\r
1167         case DimRect:\r
1168             numComponents = 2;\r
1169             break;\r
1170         case Dim3D:\r
1171             numComponents = 3;\r
1172             break;\r
1173         default:\r
1174             MissingFunctionality("texture query dimensionality");\r
1175             break;\r
1176         }\r
1177         if (isArrayedSampler(parameters.sampler))\r
1178             ++numComponents;\r
1179         if (numComponents == 1)\r
1180             resultType = makeIntType(32);\r
1181         else\r
1182             resultType = makeVectorType(makeIntType(32), numComponents);\r
1183 \r
1184         break;\r
1185     }\r
1186     case OpTextureQueryLod:\r
1187         resultType = makeVectorType(makeFloatType(32), 2);\r
1188         break;\r
1189     case OpTextureQueryLevels:\r
1190     case OpTextureQuerySamples:\r
1191         resultType = makeIntType(32);\r
1192         break;\r
1193     default:\r
1194         MissingFunctionality("Texture query op code");\r
1195     }\r
1196 \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
1204 \r
1205     return query->getResultId();\r
1206 }\r
1207 \r
1208 // Comments in header\r
1209 //Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)\r
1210 //{\r
1211 //    // Return type is only flexible type\r
1212 //    Function* opCode = (fSamplePosition, returnType);\r
1213 //\r
1214 //    Instruction* instr = (opCode, sampleIdx);\r
1215 //    setPrecision(instr, precision);\r
1216 //\r
1217 //    return instr;\r
1218 //}\r
1219 \r
1220 // Comments in header\r
1221 //Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)\r
1222 //{\r
1223 //    Op opCode = isSigned ? sBitFieldExtract\r
1224 //                                               : uBitFieldExtract;\r
1225 //\r
1226 //    if (isScalar(offset) == false || isScalar(bits) == false)\r
1227 //        MissingFunctionality("bitFieldExtract operand types");\r
1228 //\r
1229 //    // Dest and value are matching flexible types\r
1230 //    Function* opCode = (opCode, id->getType(), id->getType());\r
1231 //\r
1232 //    assert(opCode);\r
1233 //\r
1234 //    Instruction* instr = (opCode, id, offset, bits);\r
1235 //    setPrecision(instr, precision);\r
1236 //\r
1237 //    return instr;\r
1238 //}\r
1239 \r
1240 // Comments in header\r
1241 //Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)\r
1242 //{\r
1243 //    Op opCode = bitFieldInsert;\r
1244 //\r
1245 //    if (isScalar(offset) == false || isScalar(bits) == false)\r
1246 //        MissingFunctionality("bitFieldInsert operand types");\r
1247 //\r
1248 //    // Dest, base, and insert are matching flexible types\r
1249 //    Function* opCode = (opCode, base->getType(), base->getType(), base->getType());\r
1250 //\r
1251 //    assert(opCode);\r
1252 //\r
1253 //    Instruction* instr = (opCode, base, insert, offset, bits);\r
1254 //    setPrecision(instr, precision);\r
1255 //\r
1256 //    return instr;\r
1257 //}\r
1258 \r
1259 // Comments in header\r
1260 Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)\r
1261 {\r
1262     Id boolType = makeBoolType();\r
1263     Id valueType = getTypeId(value1);\r
1264 \r
1265     assert(valueType == getTypeId(value2));\r
1266     assert(! isScalar(value1));\r
1267 \r
1268     // Vectors\r
1269 \r
1270     if (isVectorType(valueType)) {\r
1271         Id boolVectorType = makeVectorType(boolType, getNumTypeComponents(valueType));\r
1272         Id boolVector;\r
1273         Op op;\r
1274         if (getMostBasicTypeClass(valueType) == OpTypeFloat)\r
1275             op = equal ? OpFOrdEqual : OpFOrdNotEqual;\r
1276         else\r
1277             op = equal ? OpIEqual : OpINotEqual;\r
1278 \r
1279         boolVector = createBinOp(op, boolVectorType, value1, value2);\r
1280         setPrecision(boolVector, precision);\r
1281 \r
1282         // Reduce vector compares with any() and all().\r
1283 \r
1284         op = equal ? OpAll : OpAny;\r
1285 \r
1286         return createUnaryOp(op, boolType, boolVector);\r
1287     }\r
1288 \r
1289     spv::MissingFunctionality("Composite comparison of non-vectors");\r
1290 \r
1291     return NoResult;\r
1292 \r
1293     // Recursively handle aggregates, which include matrices, arrays, and structures\r
1294     // and accumulate the results.\r
1295 \r
1296     // Matrices\r
1297 \r
1298     // Arrays\r
1299 \r
1300     //int numElements;\r
1301     //const llvm::ArrayType* arrayType = llvm::dyn_cast<llvm::ArrayType>(value1->getType());\r
1302     //if (arrayType)\r
1303     //    numElements = (int)arrayType->getNumElements();\r
1304     //else {\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
1309     //}\r
1310 \r
1311     //assert(numElements > 0);\r
1312 \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
1319 \r
1320     //    llvm::Value* subResult = createCompare(precision, element1, element2, equal, "comp");\r
1321 \r
1322     //    // Accumulate intermediate comparison\r
1323     //    if (element == 0)\r
1324     //        result = subResult;\r
1325     //    else {\r
1326     //        if (equal)\r
1327     //            result = builder.CreateAnd(result, subResult);\r
1328     //        else\r
1329     //            result = builder.CreateOr(result, subResult);\r
1330     //        setInstructionPrecision(result, precision);\r
1331     //    }\r
1332     //}\r
1333 \r
1334     //return result;\r
1335 }\r
1336 \r
1337 // Comments in header\r
1338 //Id Builder::createOperation(Decoration precision, Op opCode, Id operand)\r
1339 //{\r
1340 //    Op* opCode = 0;\r
1341 //\r
1342 //    // Handle special return types here.  Things that don't have same result type as parameter\r
1343 //    switch (opCode) {\r
1344 //    case fIsNan:\r
1345 //    case fIsInf:\r
1346 //        break;\r
1347 //    case fFloatBitsToInt:\r
1348 //        break;\r
1349 //    case fIntBitsTofloat:\r
1350 //        break;\r
1351 //    case fPackSnorm2x16:\r
1352 //    case fPackUnorm2x16:\r
1353 //    case fPackHalf2x16:\r
1354 //        break;\r
1355 //    case fUnpackUnorm2x16:\r
1356 //    case fUnpackSnorm2x16:\r
1357 //    case fUnpackHalf2x16:\r
1358 //        break;\r
1359 //\r
1360 //    case fFrexp:\r
1361 //    case fLdexp:\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
1368 //        break;\r
1369 //    case fLength:\r
1370 //       // scalar result type\r
1371 //       break;\r
1372 //    case any:\r
1373 //    case all:\r
1374 //        // fixed result type\r
1375 //        break;\r
1376 //    case fModF:\r
1377 //        // modf() will return a struct that the caller must decode\r
1378 //        break;\r
1379 //    default:\r
1380 //        // Unary operations that have operand and dest with same flexible type\r
1381 //        break;\r
1382 //    }\r
1383 //\r
1384 //    assert(opCode);\r
1385 //\r
1386 //    Instruction* instr = (opCode, operand);\r
1387 //    setPrecision(instr, precision);\r
1388 //\r
1389 //    return instr;\r
1390 //}\r
1391 //\r
1392 //// Comments in header\r
1393 //Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)\r
1394 //{\r
1395 //    Function* opCode = 0;\r
1396 //\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
1400 //    case fDot2:\r
1401 //    case fDot3:\r
1402 //    case fDot4:\r
1403 //        // scalar result type\r
1404 //        break;\r
1405 //    case fStep:\r
1406 //        // first argument can be scalar, return and second argument match\r
1407 //        break;\r
1408 //    case fSmoothStep:\r
1409 //        // first argument can be scalar, return and second argument match\r
1410 //        break;\r
1411 //    default:\r
1412 //        // Binary operations that have operand and dest with same flexible type\r
1413 //        break;\r
1414 //    }\r
1415 //\r
1416 //    assert(opCode);\r
1417 //\r
1418 //    Instruction* instr = (opCode, operand0, operand1);\r
1419 //    setPrecision(instr, precision);\r
1420 //\r
1421 //    return instr;\r
1422 //}\r
1423 //\r
1424 //Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)\r
1425 //{\r
1426 //    Function* opCode;\r
1427 //\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
1432 //        break;\r
1433 //    default:\r
1434 //        // Use operand0 type as result type\r
1435 //        break;\r
1436 //    }\r
1437 //\r
1438 //    assert(opCode);\r
1439 //\r
1440 //    Instruction* instr = (opCode, operand0, operand1, operand2);\r
1441 //    setPrecision(instr, precision);\r
1442 //\r
1443 //    return instr;\r
1444 //}\r
1445 \r
1446 // OpCompositeConstruct\r
1447 Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)\r
1448 {\r
1449     assert(isAggregateType(typeId) || getNumTypeComponents(typeId) > 1 && getNumTypeComponents(typeId) == constituents.size());\r
1450 \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
1455 \r
1456     return op->getResultId();\r
1457 }\r
1458 \r
1459 // Vector or scalar constructor\r
1460 Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)\r
1461 {\r
1462     Id result = 0;\r
1463     unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);\r
1464     unsigned int targetComponent = 0;\r
1465 \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
1470 \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
1476 \r
1477         unsigned int sourceSize = getNumComponents(sources[i]);\r
1478 \r
1479         unsigned int sourcesToUse = sourceSize;\r
1480         if (sourcesToUse + targetComponent > numTargetComponents)\r
1481             sourcesToUse = numTargetComponents - targetComponent;\r
1482 \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
1489             }\r
1490 \r
1491             if (numTargetComponents > 1)\r
1492                 constituents.push_back(arg);\r
1493             else\r
1494                 result = arg;\r
1495             ++targetComponent;\r
1496         }\r
1497 \r
1498         if (targetComponent >= numTargetComponents)\r
1499             break;\r
1500     }\r
1501 \r
1502     if (constituents.size() > 0)\r
1503         result = createCompositeConstruct(resultTypeId, constituents);\r
1504 \r
1505     setPrecision(result, precision);\r
1506 \r
1507     return result;\r
1508 }\r
1509 \r
1510 // Comments in header\r
1511 Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)\r
1512 {\r
1513     Id componentTypeId = getScalarTypeId(resultTypeId);\r
1514     int numCols = getTypeNumColumns(resultTypeId);\r
1515     int numRows = getTypeNumRows(resultTypeId);\r
1516 \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
1520 \r
1521     // Step 1.\r
1522 \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
1529             if (col == row)\r
1530                 ids[col][row] = one;\r
1531             else\r
1532                 ids[col][row] = zero;\r
1533         }\r
1534     }\r
1535 \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
1554             }\r
1555         }\r
1556     } else {\r
1557         // fill in the matrix in column-major order with whatever argument components are available\r
1558         int row = 0;\r
1559         int col = 0;\r
1560 \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
1567                 }\r
1568                 ids[col][row++] = argComp;\r
1569                 if (row == numRows) {\r
1570                     row = 0;\r
1571                     col++;\r
1572                 }\r
1573             }\r
1574         }\r
1575     }\r
1576 \r
1577 \r
1578     // Step 2:  Construct a matrix from that array.\r
1579     // First make the column vectors, then make the matrix.\r
1580 \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
1589     }\r
1590 \r
1591     // make the matrix\r
1592     return createCompositeConstruct(resultTypeId, matrixColumns);\r
1593 }\r
1594 \r
1595 // Comments in header\r
1596 Builder::If::If(Id cond, Builder& gb) :\r
1597     builder(gb),\r
1598     condition(cond),\r
1599     elseBlock(0)\r
1600 {\r
1601     function = &builder.getBuildPoint()->getParent();\r
1602 \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
1608 \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
1612 \r
1613     function->addBlock(thenBlock);\r
1614     builder.setBuildPoint(thenBlock);\r
1615 }\r
1616 \r
1617 // Comments in header\r
1618 void Builder::If::makeBeginElse()\r
1619 {\r
1620     // Close out the "then" by having it jump to the mergeBlock\r
1621     builder.createBranch(mergeBlock);\r
1622 \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
1626 \r
1627     // Start building the else block\r
1628     builder.setBuildPoint(elseBlock);\r
1629 }\r
1630 \r
1631 // Comments in header\r
1632 void Builder::If::makeEndIf()\r
1633 {\r
1634     // jump to the merge block\r
1635     builder.createBranch(mergeBlock);\r
1636 \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
1640     if (elseBlock)\r
1641         builder.createConditionalBranch(condition, thenBlock, elseBlock);\r
1642     else\r
1643         builder.createConditionalBranch(condition, thenBlock, mergeBlock);\r
1644 \r
1645     // add the merge block to the function\r
1646     function->addBlock(mergeBlock);\r
1647     builder.setBuildPoint(mergeBlock);\r
1648 }\r
1649 \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
1653 {\r
1654     Function& function = buildPoint->getParent();\r
1655 \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
1659 \r
1660     Block* mergeBlock = new Block(getUniqueId(), function);\r
1661 \r
1662     // make and insert the switch's selection-merge instruction\r
1663     createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);\r
1664 \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
1672     }\r
1673     buildPoint->addInstruction(switchInst);\r
1674 \r
1675     // push the merge block\r
1676     switchMerges.push(mergeBlock);\r
1677 }\r
1678 \r
1679 // Comments in header\r
1680 void Builder::addSwitchBreak()\r
1681 {\r
1682     // branch to the top of the merge block stack\r
1683     createBranch(switchMerges.top());\r
1684     createAndSetNoPredecessorBlock("post-switch-break");\r
1685 }\r
1686 \r
1687 // Comments in header\r
1688 void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)\r
1689 {\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
1695     }\r
1696     Block* block = segmentBlock[nextSegment];\r
1697     block->getParent().addBlock(block);\r
1698     setBuildPoint(block);\r
1699 }\r
1700 \r
1701 // Comments in header\r
1702 void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)\r
1703 {\r
1704     // Close out previous segment by jumping, if necessary, to next segment\r
1705     if (! buildPoint->isTerminated())\r
1706         addSwitchBreak();\r
1707 \r
1708     switchMerges.top()->getParent().addBlock(switchMerges.top());\r
1709     setBuildPoint(switchMerges.top());\r
1710 \r
1711     switchMerges.pop();\r
1712 }\r
1713 \r
1714 // Comments in header\r
1715 void Builder::makeNewLoop()\r
1716 {\r
1717     Loop loop = { };\r
1718 \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
1722 \r
1723     loops.push(loop);\r
1724 \r
1725     // Branch into the loop\r
1726     createBranch(loop.header);\r
1727 \r
1728     // Set ourselves inside the loop\r
1729     loop.function->addBlock(loop.header);\r
1730     setBuildPoint(loop.header);\r
1731 }\r
1732 \r
1733 void Builder::createLoopHeaderBranch(Id condition)\r
1734 {\r
1735     Loop loop = loops.top();\r
1736 \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
1742 }\r
1743 \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
1746 {\r
1747     Loop loop = loops.top();\r
1748 \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
1751     if (! implicit)\r
1752         createAndSetNoPredecessorBlock("post-loop-continue");\r
1753 }\r
1754 \r
1755 // Add an exit (e.g. "break") for the innermost loop that you're in\r
1756 void Builder::createLoopExit()\r
1757 {\r
1758     createBranch(loops.top().merge);\r
1759     createAndSetNoPredecessorBlock("post-loop-break");\r
1760 }\r
1761 \r
1762 // Close the innermost loop\r
1763 void Builder::closeLoop()\r
1764 {\r
1765     // Branch back to the top\r
1766     createLoopBackEdge(true);\r
1767 \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
1772 \r
1773     loops.pop();\r
1774 }\r
1775 \r
1776 void Builder::clearAccessChain()\r
1777 {\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
1786 }\r
1787 \r
1788 // Comments in header\r
1789 void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, int width, Id type)\r
1790 {\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
1797         }\r
1798     } else {\r
1799         accessChain.swizzle = swizzle;\r
1800     }\r
1801 \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
1805 \r
1806     accessChain.resultType = type;\r
1807 \r
1808     // determine if we need to track this swizzle anymore\r
1809     simplifyAccessChainSwizzle();\r
1810 }\r
1811 \r
1812 // Comments in header\r
1813 void Builder::accessChainStore(Id rvalue)\r
1814 {\r
1815     assert(accessChain.isRValue == false);\r
1816 \r
1817     Id base = collapseAccessChain();\r
1818 \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
1821     Id source;\r
1822 \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
1832 \r
1833         source = vectorInsert->getResultId();\r
1834     } else\r
1835         source = rvalue;\r
1836 \r
1837     createStore(source, base);\r
1838 }\r
1839 \r
1840 // Comments in header\r
1841 Id Builder::accessChainLoad(Decoration /*precision*/)\r
1842 {\r
1843     Id id;\r
1844 \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
1853                 else {\r
1854                     constant = false;\r
1855                     break;\r
1856                 }\r
1857             }\r
1858 \r
1859             if (constant)\r
1860                 id = createCompositeExtract(accessChain.base, accessChain.resultType, indexes);\r
1861             else {\r
1862                 // make a new function variable for this r-value\r
1863                 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");\r
1864 \r
1865                 // store into it\r
1866                 createStore(accessChain.base, lValue);\r
1867 \r
1868                 // move base to the new variable\r
1869                 accessChain.base = lValue;\r
1870                 accessChain.isRValue = false;\r
1871 \r
1872                 // load through the access chain\r
1873                 id = createLoad(collapseAccessChain());\r
1874             }\r
1875         } else\r
1876             id = accessChain.base;\r
1877     } else {\r
1878         // load through the access chain\r
1879         id = createLoad(collapseAccessChain());\r
1880     }\r
1881 \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
1890 \r
1891     return id;\r
1892 }\r
1893 \r
1894 Id Builder::accessChainGetLValue()\r
1895 {\r
1896     assert(accessChain.isRValue == false);\r
1897 \r
1898     Id lvalue = collapseAccessChain();\r
1899 \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
1905 \r
1906     return lvalue;\r
1907 }\r
1908 \r
1909 void Builder::dump(std::vector<unsigned int>& out) const\r
1910 {\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
1916     out.push_back(0);\r
1917 \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
1924     }\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
1929     }\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
1936 \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
1945 \r
1946     // The functions\r
1947     module.dump(out);\r
1948 }\r
1949 \r
1950 //\r
1951 // Protected methods.\r
1952 //\r
1953 \r
1954 Id Builder::collapseAccessChain()\r
1955 {\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
1959 \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
1964         }\r
1965 \r
1966         return accessChain.instr;\r
1967     } else\r
1968         return accessChain.base;\r
1969 }\r
1970 \r
1971 // clear out swizzle if it is redundant\r
1972 void Builder::simplifyAccessChainSwizzle()\r
1973 {\r
1974     // if swizzle has fewer components than our target, it is a writemask\r
1975     if (accessChain.swizzleTargetWidth > (int)accessChain.swizzle.size())\r
1976         return;\r
1977 \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
1981             return;\r
1982     }\r
1983 \r
1984     // otherwise, there is no need to track this swizzle\r
1985     accessChain.swizzle.clear();\r
1986     accessChain.swizzleTargetWidth = 0;\r
1987 }\r
1988 \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
1993 {\r
1994     Block* block = new Block(getUniqueId(), buildPoint->getParent());\r
1995     block->setUnreachable();\r
1996     buildPoint->getParent().addBlock(block);\r
1997     setBuildPoint(block);\r
1998 \r
1999     //if (name)\r
2000     //    addName(block->getId(), name);\r
2001 }\r
2002 \r
2003 // Comments in header\r
2004 void Builder::createBranch(Block* block)\r
2005 {\r
2006     Instruction* branch = new Instruction(OpBranch);\r
2007     branch->addIdOperand(block->getId());\r
2008     buildPoint->addInstruction(branch);\r
2009     block->addPredecessor(buildPoint);\r
2010 }\r
2011 \r
2012 void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)\r
2013 {\r
2014     Instruction* merge = new Instruction(mergeCode);\r
2015     merge->addIdOperand(mergeBlock->getId());\r
2016     merge->addImmediateOperand(control);\r
2017     buildPoint->addInstruction(merge);\r
2018 }\r
2019 \r
2020 void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)\r
2021 {\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
2029 }\r
2030 \r
2031 void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<Instruction*>& instructions) const\r
2032 {\r
2033     for (int i = 0; i < (int)instructions.size(); ++i) {\r
2034         instructions[i]->dump(out);\r
2035     }\r
2036 }\r
2037 \r
2038 void MissingFunctionality(const char* fun)\r
2039 {\r
2040     printf("Missing functionality: %s\n", fun);\r
2041     exit(1);\r
2042 }\r
2043 \r
2044 void ValidationError(const char* error)\r
2045 {\r
2046     printf("Validation Error: %s\n", error);\r
2047 }\r
2048 \r
2049 }; // end spv namespace\r