OSDN Git Service

SpirvShader: Add SIMD namespace.
[android-x86/external-swiftshader.git] / src / Pipeline / SpirvShader.cpp
1 // Copyright 2018 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <spirv/unified1/spirv.hpp>
16 #include "SpirvShader.hpp"
17 #include "System/Math.hpp"
18 #include "Vulkan/VkDebug.hpp"
19 #include "Device/Config.hpp"
20
21 namespace sw
22 {
23         volatile int SpirvShader::serialCounter = 1;    // Start at 1, 0 is invalid shader.
24
25         SpirvShader::SpirvShader(InsnStore const &insns)
26                         : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
27                           outputs{MAX_INTERFACE_COMPONENTS},
28                           serialID{serialCounter++}, modes{}
29         {
30                 // Simplifying assumptions (to be satisfied by earlier transformations)
31                 // - There is exactly one entrypoint in the module, and it's the one we want
32                 // - The only input/output OpVariables present are those used by the entrypoint
33
34                 for (auto insn : *this)
35                 {
36                         switch (insn.opcode())
37                         {
38                         case spv::OpExecutionMode:
39                                 ProcessExecutionMode(insn);
40                                 break;
41
42                         case spv::OpDecorate:
43                         {
44                                 TypeOrObjectID targetId = insn.word(1);
45                                 auto decoration = static_cast<spv::Decoration>(insn.word(2));
46                                 decorations[targetId].Apply(
47                                                 decoration,
48                                                 insn.wordCount() > 3 ? insn.word(3) : 0);
49
50                                 if (decoration == spv::DecorationCentroid)
51                                         modes.NeedsCentroid = true;
52                                 break;
53                         }
54
55                         case spv::OpMemberDecorate:
56                         {
57                                 TypeID targetId = insn.word(1);
58                                 auto memberIndex = insn.word(2);
59                                 auto &d = memberDecorations[targetId];
60                                 if (memberIndex >= d.size())
61                                         d.resize(memberIndex + 1);    // on demand; exact size would require another pass...
62                                 auto decoration = static_cast<spv::Decoration>(insn.word(3));
63                                 d[memberIndex].Apply(
64                                                 decoration,
65                                                 insn.wordCount() > 4 ? insn.word(4) : 0);
66
67                                 if (decoration == spv::DecorationCentroid)
68                                         modes.NeedsCentroid = true;
69                                 break;
70                         }
71
72                         case spv::OpDecorationGroup:
73                                 // Nothing to do here. We don't need to record the definition of the group; we'll just have
74                                 // the bundle of decorations float around. If we were to ever walk the decorations directly,
75                                 // we might think about introducing this as a real Object.
76                                 break;
77
78                         case spv::OpGroupDecorate:
79                         {
80                                 auto const &srcDecorations = decorations[insn.word(1)];
81                                 for (auto i = 2u; i < insn.wordCount(); i++)
82                                 {
83                                         // remaining operands are targets to apply the group to.
84                                         decorations[insn.word(i)].Apply(srcDecorations);
85                                 }
86                                 break;
87                         }
88
89                         case spv::OpGroupMemberDecorate:
90                         {
91                                 auto const &srcDecorations = decorations[insn.word(1)];
92                                 for (auto i = 2u; i < insn.wordCount(); i += 2)
93                                 {
94                                         // remaining operands are pairs of <id>, literal for members to apply to.
95                                         auto &d = memberDecorations[insn.word(i)];
96                                         auto memberIndex = insn.word(i + 1);
97                                         if (memberIndex >= d.size())
98                                                 d.resize(memberIndex + 1);    // on demand resize, see above...
99                                         d[memberIndex].Apply(srcDecorations);
100                                 }
101                                 break;
102                         }
103
104                         case spv::OpTypeVoid:
105                         case spv::OpTypeBool:
106                         case spv::OpTypeInt:
107                         case spv::OpTypeFloat:
108                         case spv::OpTypeVector:
109                         case spv::OpTypeMatrix:
110                         case spv::OpTypeImage:
111                         case spv::OpTypeSampler:
112                         case spv::OpTypeSampledImage:
113                         case spv::OpTypeArray:
114                         case spv::OpTypeRuntimeArray:
115                         case spv::OpTypeStruct:
116                         case spv::OpTypePointer:
117                         case spv::OpTypeFunction:
118                         {
119                                 TypeID resultId = insn.word(1);
120                                 auto &type = types[resultId];
121                                 type.definition = insn;
122                                 type.sizeInComponents = ComputeTypeSize(insn);
123
124                                 // A structure is a builtin block if it has a builtin
125                                 // member. All members of such a structure are builtins.
126                                 switch (insn.opcode())
127                                 {
128                                 case spv::OpTypeStruct:
129                                 {
130                                         auto d = memberDecorations.find(resultId);
131                                         if (d != memberDecorations.end())
132                                         {
133                                                 for (auto &m : d->second)
134                                                 {
135                                                         if (m.HasBuiltIn)
136                                                         {
137                                                                 type.isBuiltInBlock = true;
138                                                                 break;
139                                                         }
140                                                 }
141                                         }
142                                         break;
143                                 }
144                                 case spv::OpTypePointer:
145                                 {
146                                         TypeID elementTypeId = insn.word(3);
147                                         type.element = elementTypeId;
148                                         type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
149                                         type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
150                                         break;
151                                 }
152                                 case spv::OpTypeVector:
153                                 case spv::OpTypeMatrix:
154                                 case spv::OpTypeArray:
155                                 case spv::OpTypeRuntimeArray:
156                                 {
157                                         TypeID elementTypeId = insn.word(2);
158                                         type.element = elementTypeId;
159                                         break;
160                                 }
161                                 default:
162                                         break;
163                                 }
164                                 break;
165                         }
166
167                         case spv::OpVariable:
168                         {
169                                 TypeID typeId = insn.word(1);
170                                 ObjectID resultId = insn.word(2);
171                                 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
172                                 if (insn.wordCount() > 4)
173                                         UNIMPLEMENTED("Variable initializers not yet supported");
174
175                                 auto &object = defs[resultId];
176                                 object.kind = Object::Kind::Variable;
177                                 object.definition = insn;
178                                 object.type = typeId;
179                                 object.pointerBase = insn.word(2);      // base is itself
180
181                                 // Register builtins
182                                 switch (storageClass)
183                                 {
184                                         case spv::StorageClassInput:
185                                         case spv::StorageClassOutput:
186                                                 ProcessInterfaceVariable(object);
187                                                 break;
188                                         default:
189                                                 UNIMPLEMENTED("Unhandled storage class %d for OpVariable", (int)storageClass);
190                                 }
191                                 break;
192                         }
193
194                         case spv::OpConstant:
195                                 CreateConstant(insn).constantValue[0] = insn.word(3);
196                                 break;
197                         case spv::OpConstantFalse:
198                                 CreateConstant(insn).constantValue[0] = 0;              // represent boolean false as zero
199                                 break;
200                         case spv::OpConstantTrue:
201                                 CreateConstant(insn).constantValue[0] = ~0u;    // represent boolean true as all bits set
202                                 break;
203                         case spv::OpConstantNull:
204                         {
205                                 // OpConstantNull forms a constant of arbitrary type, all zeros.
206                                 auto &object = CreateConstant(insn);
207                                 auto &objectTy = getType(object.type);
208                                 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
209                                 {
210                                         object.constantValue[i] = 0;
211                                 }
212                                 break;
213                         }
214                         case spv::OpConstantComposite:
215                         {
216                                 auto &object = CreateConstant(insn);
217                                 auto offset = 0u;
218                                 for (auto i = 0u; i < insn.wordCount() - 3; i++)
219                                 {
220                                         auto &constituent = getObject(insn.word(i + 3));
221                                         auto &constituentTy = getType(constituent.type);
222                                         for (auto j = 0u; j < constituentTy.sizeInComponents; j++)
223                                                 object.constantValue[offset++] = constituent.constantValue[j];
224                                 }
225                                 break;
226                         }
227
228                         case spv::OpCapability:
229                                 // Various capabilities will be declared, but none affect our code generation at this point.
230                         case spv::OpMemoryModel:
231                                 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
232                         case spv::OpEntryPoint:
233                         case spv::OpFunction:
234                         case spv::OpFunctionEnd:
235                                 // Due to preprocessing, the entrypoint and its function provide no value.
236                                 break;
237                         case spv::OpExtInstImport:
238                                 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
239                                 // Valid shaders will not attempt to import any other instruction sets.
240                         case spv::OpName:
241                         case spv::OpMemberName:
242                         case spv::OpSource:
243                         case spv::OpSourceContinued:
244                         case spv::OpSourceExtension:
245                                 // No semantic impact
246                                 break;
247
248                         case spv::OpFunctionParameter:
249                         case spv::OpFunctionCall:
250                         case spv::OpSpecConstant:
251                         case spv::OpSpecConstantComposite:
252                         case spv::OpSpecConstantFalse:
253                         case spv::OpSpecConstantOp:
254                         case spv::OpSpecConstantTrue:
255                                 // These should have all been removed by preprocessing passes. If we see them here,
256                                 // our assumptions are wrong and we will probably generate wrong code.
257                                 UNIMPLEMENTED("These instructions should have already been lowered.");
258                                 break;
259
260                         case spv::OpLoad:
261                         case spv::OpAccessChain:
262                         case spv::OpCompositeConstruct:
263                         case spv::OpCompositeInsert:
264                         case spv::OpCompositeExtract:
265                         case spv::OpVectorShuffle:
266                                 // Instructions that yield an ssavalue.
267                         {
268                                 TypeID typeId = insn.word(1);
269                                 ObjectID resultId = insn.word(2);
270                                 auto &object = defs[resultId];
271                                 object.type = typeId;
272                                 object.kind = Object::Kind::Value;
273                                 object.definition = insn;
274
275                                 if (insn.opcode() == spv::OpAccessChain)
276                                 {
277                                         // interior ptr has two parts:
278                                         // - logical base ptr, common across all lanes and known at compile time
279                                         // - per-lane offset
280                                         ObjectID baseId = insn.word(3);
281                                         object.pointerBase = getObject(baseId).pointerBase;
282                                 }
283                                 break;
284                         }
285
286                         case spv::OpStore:
287                         case spv::OpReturn:
288                                 // Don't need to do anything during analysis pass
289                                 break;
290
291                         case spv::OpKill:
292                                 modes.ContainsKill = true;
293                                 break;
294
295                         default:
296                                 printf("Warning: ignored opcode %u\n", insn.opcode());
297                                 break;    // This is OK, these passes are intentionally partial
298                         }
299                 }
300         }
301
302         SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
303         {
304                 TypeID typeId = insn.word(1);
305                 ObjectID resultId = insn.word(2);
306                 auto &object = defs[resultId];
307                 auto &objectTy = getType(typeId);
308                 object.type = typeId;
309                 object.kind = Object::Kind::Constant;
310                 object.definition = insn;
311                 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
312                 return object;
313         }
314
315         void SpirvShader::ProcessInterfaceVariable(Object &object)
316         {
317                 auto &objectTy = getType(object.type);
318                 assert(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
319
320                 assert(objectTy.definition.opcode() == spv::OpTypePointer);
321                 auto pointeeTy = getType(objectTy.element);
322
323                 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
324                 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
325
326                 assert(object.definition.opcode() == spv::OpVariable);
327                 ObjectID resultId = object.definition.word(2);
328
329                 if (objectTy.isBuiltInBlock)
330                 {
331                         // walk the builtin block, registering each of its members separately.
332                         auto m = memberDecorations.find(objectTy.element);
333                         assert(m != memberDecorations.end());        // otherwise we wouldn't have marked the type chain
334                         auto &structType = pointeeTy.definition;
335                         auto offset = 0u;
336                         auto word = 2u;
337                         for (auto &member : m->second)
338                         {
339                                 auto &memberType = getType(structType.word(word));
340
341                                 if (member.HasBuiltIn)
342                                 {
343                                         builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
344                                 }
345
346                                 offset += memberType.sizeInComponents;
347                                 ++word;
348                         }
349                         return;
350                 }
351
352                 auto d = decorations.find(resultId);
353                 if (d != decorations.end() && d->second.HasBuiltIn)
354                 {
355                         builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
356                 }
357                 else
358                 {
359                         object.kind = Object::Kind::InterfaceVariable;
360                         VisitInterface(resultId,
361                                                    [&userDefinedInterface](Decorations const &d, AttribType type) {
362                                                            // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
363                                                            auto scalarSlot = (d.Location << 2) | d.Component;
364                                                            assert(scalarSlot >= 0 &&
365                                                                           scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
366
367                                                            auto &slot = userDefinedInterface[scalarSlot];
368                                                            slot.Type = type;
369                                                            slot.Flat = d.Flat;
370                                                            slot.NoPerspective = d.NoPerspective;
371                                                            slot.Centroid = d.Centroid;
372                                                    });
373                 }
374         }
375
376         void SpirvShader::ProcessExecutionMode(InsnIterator insn)
377         {
378                 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
379                 switch (mode)
380                 {
381                 case spv::ExecutionModeEarlyFragmentTests:
382                         modes.EarlyFragmentTests = true;
383                         break;
384                 case spv::ExecutionModeDepthReplacing:
385                         modes.DepthReplacing = true;
386                         break;
387                 case spv::ExecutionModeDepthGreater:
388                         modes.DepthGreater = true;
389                         break;
390                 case spv::ExecutionModeDepthLess:
391                         modes.DepthLess = true;
392                         break;
393                 case spv::ExecutionModeDepthUnchanged:
394                         modes.DepthUnchanged = true;
395                         break;
396                 case spv::ExecutionModeLocalSize:
397                         modes.LocalSizeX = insn.word(3);
398                         modes.LocalSizeZ = insn.word(5);
399                         modes.LocalSizeY = insn.word(4);
400                         break;
401                 case spv::ExecutionModeOriginUpperLeft:
402                         // This is always the case for a Vulkan shader. Do nothing.
403                         break;
404                 default:
405                         UNIMPLEMENTED("No other execution modes are permitted");
406                 }
407         }
408
409         uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
410         {
411                 // Types are always built from the bottom up (with the exception of forward ptrs, which
412                 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
413                 // already been described (and so their sizes determined)
414                 switch (insn.opcode())
415                 {
416                 case spv::OpTypeVoid:
417                 case spv::OpTypeSampler:
418                 case spv::OpTypeImage:
419                 case spv::OpTypeSampledImage:
420                 case spv::OpTypeFunction:
421                 case spv::OpTypeRuntimeArray:
422                         // Objects that don't consume any space.
423                         // Descriptor-backed objects currently only need exist at compile-time.
424                         // Runtime arrays don't appear in places where their size would be interesting
425                         return 0;
426
427                 case spv::OpTypeBool:
428                 case spv::OpTypeFloat:
429                 case spv::OpTypeInt:
430                         // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
431                         // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
432                         return 1;
433
434                 case spv::OpTypeVector:
435                 case spv::OpTypeMatrix:
436                         // Vectors and matrices both consume element count * element size.
437                         return getType(insn.word(2)).sizeInComponents * insn.word(3);
438
439                 case spv::OpTypeArray:
440                 {
441                         // Element count * element size. Array sizes come from constant ids.
442                         auto arraySize = GetConstantInt(insn.word(3));
443                         return getType(insn.word(2)).sizeInComponents * arraySize;
444                 }
445
446                 case spv::OpTypeStruct:
447                 {
448                         uint32_t size = 0;
449                         for (uint32_t i = 2u; i < insn.wordCount(); i++)
450                         {
451                                 size += getType(insn.word(i)).sizeInComponents;
452                         }
453                         return size;
454                 }
455
456                 case spv::OpTypePointer:
457                         // Runtime representation of a pointer is a per-lane index.
458                         // Note: clients are expected to look through the pointer if they want the pointee size instead.
459                         return 1;
460
461                 default:
462                         // Some other random insn.
463                         UNIMPLEMENTED("Only types are supported");
464                         return 0;
465                 }
466         }
467
468         template<typename F>
469         int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
470         {
471                 // Recursively walks variable definition and its type tree, taking into account
472                 // any explicit Location or Component decorations encountered; where explicit
473                 // Locations or Components are not specified, assigns them sequentially.
474                 // Collected decorations are carried down toward the leaves and across
475                 // siblings; Effect of decorations intentionally does not flow back up the tree.
476                 //
477                 // F is a functor to be called with the effective decoration set for every component.
478                 //
479                 // Returns the next available location, and calls f().
480
481                 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
482
483                 ApplyDecorationsForId(&d, id);
484
485                 auto const &obj = getType(id);
486                 switch (obj.definition.opcode())
487                 {
488                 case spv::OpTypePointer:
489                         return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
490                 case spv::OpTypeMatrix:
491                         for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
492                         {
493                                 // consumes same components of N consecutive locations
494                                 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
495                         }
496                         return d.Location;
497                 case spv::OpTypeVector:
498                         for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
499                         {
500                                 // consumes N consecutive components in the same location
501                                 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
502                         }
503                         return d.Location + 1;
504                 case spv::OpTypeFloat:
505                         f(d, ATTRIBTYPE_FLOAT);
506                         return d.Location + 1;
507                 case spv::OpTypeInt:
508                         f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
509                         return d.Location + 1;
510                 case spv::OpTypeBool:
511                         f(d, ATTRIBTYPE_UINT);
512                         return d.Location + 1;
513                 case spv::OpTypeStruct:
514                 {
515                         // iterate over members, which may themselves have Location/Component decorations
516                         for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
517                         {
518                                 ApplyDecorationsForIdMember(&d, id, i);
519                                 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
520                                 d.Component = 0;    // Implicit locations always have component=0
521                         }
522                         return d.Location;
523                 }
524                 case spv::OpTypeArray:
525                 {
526                         auto arraySize = GetConstantInt(obj.definition.word(3));
527                         for (auto i = 0u; i < arraySize; i++)
528                         {
529                                 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
530                         }
531                         return d.Location;
532                 }
533                 default:
534                         // Intentionally partial; most opcodes do not participate in type hierarchies
535                         return 0;
536                 }
537         }
538
539         template<typename F>
540         void SpirvShader::VisitInterface(ObjectID id, F f) const
541         {
542                 // Walk a variable definition and call f for each component in it.
543                 Decorations d{};
544                 ApplyDecorationsForId(&d, id);
545
546                 auto def = getObject(id).definition;
547                 assert(def.opcode() == spv::OpVariable);
548                 VisitInterfaceInner<F>(def.word(1), d, f);
549         }
550
551         SIMD::Int SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
552         {
553                 // TODO: think about explicit layout (UBO/SSBO) storage classes
554                 // TODO: avoid doing per-lane work in some cases if we can?
555
556                 int constantOffset = 0;
557                 SIMD::Int dynamicOffset = SIMD::Int(0);
558                 auto &baseObject = getObject(id);
559                 TypeID typeId = getType(baseObject.type).element;
560
561                 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
562                 // Start with its offset and build from there.
563                 if (baseObject.kind == Object::Kind::Value)
564                         dynamicOffset += As<SIMD::Int>(routine->getIntermediate(id)[0]);
565
566                 for (auto i = 0u; i < numIndexes; i++)
567                 {
568                         auto & type = getType(typeId);
569                         switch (type.definition.opcode())
570                         {
571                         case spv::OpTypeStruct:
572                         {
573                                 int memberIndex = GetConstantInt(indexIds[i]);
574                                 int offsetIntoStruct = 0;
575                                 for (auto j = 0; j < memberIndex; j++) {
576                                         auto memberType = type.definition.word(2u + j);
577                                         offsetIntoStruct += getType(memberType).sizeInComponents;
578                                 }
579                                 constantOffset += offsetIntoStruct;
580                                 typeId = type.definition.word(2u + memberIndex);
581                                 break;
582                         }
583
584                         case spv::OpTypeVector:
585                         case spv::OpTypeMatrix:
586                         case spv::OpTypeArray:
587                         {
588                                 auto stride = getType(type.element).sizeInComponents;
589                                 auto & obj = getObject(indexIds[i]);
590                                 if (obj.kind == Object::Kind::Constant)
591                                         constantOffset += stride * GetConstantInt(indexIds[i]);
592                                 else
593                                         dynamicOffset += SIMD::Int(stride) * As<SIMD::Int>(routine->getIntermediate(indexIds[i])[0]);
594                                 typeId = type.element;
595                                 break;
596                         }
597
598                         default:
599                                 UNIMPLEMENTED("Unexpected type in WalkAccessChain");
600                         }
601                 }
602
603                 return dynamicOffset + SIMD::Int(constantOffset);
604         }
605
606         uint32_t SpirvShader::WalkLiteralAccessChain(TypeID typeId, uint32_t numIndexes, uint32_t const *indexes) const
607         {
608                 uint32_t constantOffset = 0;
609
610                 for (auto i = 0u; i < numIndexes; i++)
611                 {
612                         auto & type = getType(typeId);
613                         switch (type.definition.opcode())
614                         {
615                         case spv::OpTypeStruct:
616                         {
617                                 int memberIndex = indexes[i];
618                                 int offsetIntoStruct = 0;
619                                 for (auto j = 0; j < memberIndex; j++) {
620                                         auto memberType = type.definition.word(2u + j);
621                                         offsetIntoStruct += getType(memberType).sizeInComponents;
622                                 }
623                                 constantOffset += offsetIntoStruct;
624                                 typeId = type.definition.word(2u + memberIndex);
625                                 break;
626                         }
627
628                         case spv::OpTypeVector:
629                         case spv::OpTypeMatrix:
630                         case spv::OpTypeArray:
631                         {
632                                 auto elementType = type.definition.word(2);
633                                 auto stride = getType(elementType).sizeInComponents;
634                                 constantOffset += stride * indexes[i];
635                                 typeId = elementType;
636                                 break;
637                         }
638
639                         default:
640                                 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
641                         }
642                 }
643
644                 return constantOffset;
645         }
646
647         void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
648         {
649                 switch (decoration)
650                 {
651                 case spv::DecorationLocation:
652                         HasLocation = true;
653                         Location = static_cast<int32_t>(arg);
654                         break;
655                 case spv::DecorationComponent:
656                         HasComponent = true;
657                         Component = arg;
658                         break;
659                 case spv::DecorationBuiltIn:
660                         HasBuiltIn = true;
661                         BuiltIn = static_cast<spv::BuiltIn>(arg);
662                         break;
663                 case spv::DecorationFlat:
664                         Flat = true;
665                         break;
666                 case spv::DecorationNoPerspective:
667                         NoPerspective = true;
668                         break;
669                 case spv::DecorationCentroid:
670                         Centroid = true;
671                         break;
672                 case spv::DecorationBlock:
673                         Block = true;
674                         break;
675                 case spv::DecorationBufferBlock:
676                         BufferBlock = true;
677                         break;
678                 default:
679                         // Intentionally partial, there are many decorations we just don't care about.
680                         break;
681                 }
682         }
683
684         void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
685         {
686                 // Apply a decoration group to this set of decorations
687                 if (src.HasBuiltIn)
688                 {
689                         HasBuiltIn = true;
690                         BuiltIn = src.BuiltIn;
691                 }
692
693                 if (src.HasLocation)
694                 {
695                         HasLocation = true;
696                         Location = src.Location;
697                 }
698
699                 if (src.HasComponent)
700                 {
701                         HasComponent = true;
702                         Component = src.Component;
703                 }
704
705                 Flat |= src.Flat;
706                 NoPerspective |= src.NoPerspective;
707                 Centroid |= src.Centroid;
708                 Block |= src.Block;
709                 BufferBlock |= src.BufferBlock;
710         }
711
712         void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
713         {
714                 auto it = decorations.find(id);
715                 if (it != decorations.end())
716                         d->Apply(it->second);
717         }
718
719         void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const
720         {
721                 auto it = memberDecorations.find(id);
722                 if (it != memberDecorations.end() && member < it->second.size())
723                 {
724                         d->Apply(it->second[member]);
725                 }
726         }
727
728         uint32_t SpirvShader::GetConstantInt(ObjectID id) const
729         {
730                 // Slightly hackish access to constants very early in translation.
731                 // General consumption of constants by other instructions should
732                 // probably be just lowered to Reactor.
733
734                 // TODO: not encountered yet since we only use this for array sizes etc,
735                 // but is possible to construct integer constant 0 via OpConstantNull.
736                 auto insn = getObject(id).definition;
737                 assert(insn.opcode() == spv::OpConstant);
738                 assert(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
739                 return insn.word(3);
740         }
741
742         // emit-time
743
744         void SpirvShader::emitProlog(SpirvRoutine *routine) const
745         {
746                 for (auto insn : *this)
747                 {
748                         switch (insn.opcode())
749                         {
750                         case spv::OpVariable:
751                         {
752                                 ObjectID resultId = insn.word(2);
753                                 auto &object = getObject(resultId);
754                                 auto &objectTy = getType(object.type);
755                                 auto &pointeeTy = getType(objectTy.element);
756                                 // TODO: what to do about zero-slot objects?
757                                 if (pointeeTy.sizeInComponents > 0)
758                                 {
759                                         routine->createLvalue(insn.word(2), pointeeTy.sizeInComponents);
760                                 }
761                                 break;
762                         }
763                         default:
764                                 // Nothing else produces interface variables, so can all be safely ignored.
765                                 break;
766                         }
767                 }
768         }
769
770         void SpirvShader::emit(SpirvRoutine *routine) const
771         {
772                 for (auto insn : *this)
773                 {
774                         switch (insn.opcode())
775                         {
776                         case spv::OpTypeVoid:
777                         case spv::OpTypeInt:
778                         case spv::OpTypeFloat:
779                         case spv::OpTypeBool:
780                         case spv::OpTypeVector:
781                         case spv::OpTypeArray:
782                         case spv::OpTypeRuntimeArray:
783                         case spv::OpTypeMatrix:
784                         case spv::OpTypeStruct:
785                         case spv::OpTypePointer:
786                         case spv::OpTypeFunction:
787                         case spv::OpExecutionMode:
788                         case spv::OpMemoryModel:
789                         case spv::OpFunction:
790                         case spv::OpFunctionEnd:
791                         case spv::OpConstant:
792                         case spv::OpConstantNull:
793                         case spv::OpConstantTrue:
794                         case spv::OpConstantFalse:
795                         case spv::OpConstantComposite:
796                         case spv::OpExtension:
797                         case spv::OpCapability:
798                         case spv::OpEntryPoint:
799                         case spv::OpExtInstImport:
800                         case spv::OpDecorate:
801                         case spv::OpMemberDecorate:
802                         case spv::OpGroupDecorate:
803                         case spv::OpGroupMemberDecorate:
804                         case spv::OpDecorationGroup:
805                         case spv::OpName:
806                         case spv::OpMemberName:
807                         case spv::OpSource:
808                         case spv::OpSourceContinued:
809                         case spv::OpSourceExtension:
810                                 // Nothing to do at emit time. These are either fully handled at analysis time,
811                                 // or don't require any work at all.
812                                 break;
813
814                         case spv::OpVariable:
815                         {
816                                 ObjectID resultId = insn.word(2);
817                                 auto &object = getObject(resultId);
818                                 auto &objectTy = getType(object.type);
819                                 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassInput)
820                                 {
821                                         auto &dst = routine->getValue(resultId);
822                                         int offset = 0;
823                                         VisitInterface(resultId,
824                                                                    [&](Decorations const &d, AttribType type) {
825                                                                            auto scalarSlot = d.Location << 2 | d.Component;
826                                                                            dst[offset++] = routine->inputs[scalarSlot];
827                                                                    });
828                                 }
829                                 break;
830                         }
831                         case spv::OpLoad:
832                         {
833                                 ObjectID objectId = insn.word(2);
834                                 ObjectID pointerId = insn.word(3);
835                                 auto &object = getObject(objectId);
836                                 auto &objectTy = getType(object.type);
837                                 auto &pointer = getObject(pointerId);
838                                 auto &pointerBase = getObject(pointer.pointerBase);
839                                 auto &pointerBaseTy = getType(pointerBase.type);
840
841                                 ASSERT(getType(pointer.type).element == object.type);
842                                 ASSERT(TypeID(insn.word(1)) == object.type);
843
844                                 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
845                                         pointerBaseTy.storageClass == spv::StorageClassUniform ||
846                                         pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
847                                 {
848                                         UNIMPLEMENTED("Descriptor-backed load not yet implemented");
849                                 }
850
851                                 auto &ptrBase = routine->getValue(pointer.pointerBase);
852                                 auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
853
854                                 if (pointer.kind == Object::Kind::Value)
855                                 {
856                                         auto offsets = As<SIMD::Int>(routine->getIntermediate(insn.word(3))[0]);
857                                         for (auto i = 0u; i < objectTy.sizeInComponents; i++)
858                                         {
859                                                 // i wish i had a Float,Float,Float,Float constructor here..
860                                                 SIMD::Float v;
861                                                 for (int j = 0; j < SIMD::Width; j++)
862                                                 {
863                                                         Int offset = Int(i) + Extract(offsets, j);
864                                                         v = Insert(v, Extract(ptrBase[offset], j), j);
865                                                 }
866                                                 dst.emplace(i, v);
867                                         }
868                                 }
869                                 else
870                                 {
871                                         // no divergent offsets to worry about
872                                         for (auto i = 0u; i < objectTy.sizeInComponents; i++)
873                                         {
874                                                 dst.emplace(i, ptrBase[i]);
875                                         }
876                                 }
877                                 break;
878                         }
879                         case spv::OpAccessChain:
880                         {
881                                 TypeID typeId = insn.word(1);
882                                 ObjectID objectId = insn.word(2);
883                                 ObjectID baseId = insn.word(3);
884                                 auto &object = getObject(objectId);
885                                 auto &type = getType(typeId);
886                                 auto &pointerBase = getObject(object.pointerBase);
887                                 auto &pointerBaseTy = getType(pointerBase.type);
888                                 ASSERT(type.sizeInComponents == 1);
889                                 ASSERT(getObject(baseId).pointerBase == object.pointerBase);
890
891                                 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
892                                         pointerBaseTy.storageClass == spv::StorageClassUniform ||
893                                         pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
894                                 {
895                                         UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
896                                 }
897                                 auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
898                                 dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
899                                 break;
900                         }
901                         case spv::OpStore:
902                         {
903                                 ObjectID pointerId = insn.word(1);
904                                 ObjectID objectId = insn.word(2);
905                                 auto &object = getObject(objectId);
906                                 auto &pointer = getObject(pointerId);
907                                 auto &pointerTy = getType(pointer.type);
908                                 auto &elementTy = getType(pointerTy.element);
909                                 auto &pointerBase = getObject(pointer.pointerBase);
910                                 auto &pointerBaseTy = getType(pointerBase.type);
911
912                                 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
913                                         pointerBaseTy.storageClass == spv::StorageClassUniform ||
914                                         pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
915                                 {
916                                         UNIMPLEMENTED("Descriptor-backed store not yet implemented");
917                                 }
918
919                                 auto &ptrBase = routine->getValue(pointer.pointerBase);
920
921                                 if (object.kind == Object::Kind::Constant)
922                                 {
923                                         auto src = reinterpret_cast<float *>(object.constantValue.get());
924
925                                         if (pointer.kind == Object::Kind::Value)
926                                         {
927                                                 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
928                                                 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
929                                                 {
930                                                         // Scattered store
931                                                         for (int j = 0; j < SIMD::Width; j++)
932                                                         {
933                                                                 auto dst = ptrBase[Int(i) + Extract(offsets, j)];
934                                                                 dst = Insert(dst, Float(src[i]), j);
935                                                         }
936                                                 }
937                                         }
938                                         else
939                                         {
940                                                 // no divergent offsets
941                                                 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
942                                                 {
943                                                         ptrBase[i] = RValue<SIMD::Float>(src[i]);
944                                                 }
945                                         }
946                                 }
947                                 else
948                                 {
949                                         auto &src = routine->getIntermediate(objectId);
950
951                                         if (pointer.kind == Object::Kind::Value)
952                                         {
953                                                 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
954                                                 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
955                                                 {
956                                                         // Scattered store
957                                                         for (int j = 0; j < SIMD::Width; j++)
958                                                         {
959                                                                 auto dst = ptrBase[Int(i) + Extract(offsets, j)];
960                                                                 dst = Insert(dst, Extract(src[i], j), j);
961                                                         }
962                                                 }
963                                         }
964                                         else
965                                         {
966                                                 // no divergent offsets
967                                                 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
968                                                 {
969                                                         ptrBase[i] = src[i];
970                                                 }
971                                         }
972                                 }
973                                 break;
974                         }
975                         case spv::OpCompositeConstruct:
976                         {
977                                 auto &type = getType(insn.word(1));
978                                 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
979                                 auto offset = 0u;
980
981                                 for (auto i = 0u; i < insn.wordCount() - 3; i++)
982                                 {
983                                         ObjectID srcObjectId = insn.word(3u + i);
984                                         auto & srcObject = getObject(srcObjectId);
985                                         auto & srcObjectTy = getType(srcObject.type);
986                                         GenericValue srcObjectAccess(this, routine, srcObjectId);
987
988                                         for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
989                                                 dst.emplace(offset++, srcObjectAccess[j]);
990                                 }
991                                 break;
992                         }
993                         case spv::OpCompositeInsert:
994                         {
995                                 TypeID resultTypeId = insn.word(1);
996                                 auto &type = getType(resultTypeId);
997                                 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
998                                 auto &newPartObject = getObject(insn.word(3));
999                                 auto &newPartObjectTy = getType(newPartObject.type);
1000                                 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
1001
1002                                 GenericValue srcObjectAccess(this, routine, insn.word(4));
1003                                 GenericValue newPartObjectAccess(this, routine, insn.word(3));
1004
1005                                 // old components before
1006                                 for (auto i = 0u; i < firstNewComponent; i++)
1007                                         dst.emplace(i, srcObjectAccess[i]);
1008                                 // new part
1009                                 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
1010                                         dst.emplace(firstNewComponent + i, newPartObjectAccess[i]);
1011                                 // old components after
1012                                 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
1013                                         dst.emplace(i, srcObjectAccess[i]);
1014                                 break;
1015                         }
1016                         case spv::OpCompositeExtract:
1017                         {
1018                                 auto &type = getType(insn.word(1));
1019                                 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1020                                 auto &compositeObject = getObject(insn.word(3));
1021                                 TypeID compositeTypeId = compositeObject.definition.word(1);
1022                                 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
1023
1024                                 GenericValue compositeObjectAccess(this, routine, insn.word(3));
1025                                 for (auto i = 0u; i < type.sizeInComponents; i++)
1026                                         dst.emplace(i, compositeObjectAccess[firstComponent + i]);
1027                                 break;
1028                         }
1029                         case spv::OpVectorShuffle:
1030                         {
1031                                 auto &type = getType(insn.word(1));
1032                                 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1033
1034                                 GenericValue firstHalfAccess(this, routine, insn.word(3));
1035                                 GenericValue secondHalfAccess(this, routine, insn.word(4));
1036
1037                                 for (auto i = 0u; i < type.sizeInComponents; i++)
1038                                 {
1039                                         auto selector = insn.word(5 + i);
1040                                         if (selector == static_cast<uint32_t>(-1))
1041                                         {
1042                                                 // Undefined value. Until we decide to do real undef values, zero is as good
1043                                                 // a value as any
1044                                                 dst.emplace(i, RValue<SIMD::Float>(0.0f));
1045                                         }
1046                                         else if (selector < type.sizeInComponents)
1047                                         {
1048                                                 dst.emplace(i, firstHalfAccess[selector]);
1049                                         }
1050                                         else
1051                                         {
1052                                                 dst.emplace(i, secondHalfAccess[selector - type.sizeInComponents]);
1053                                         }
1054                                 }
1055                                 break;
1056                         }
1057                         default:
1058                                 printf("emit: ignoring opcode %d\n", insn.opcode());
1059                                 break;
1060                         }
1061                 }
1062         }
1063
1064         void SpirvShader::emitEpilog(SpirvRoutine *routine) const
1065         {
1066                 for (auto insn : *this)
1067                 {
1068                         switch (insn.opcode())
1069                         {
1070                         case spv::OpVariable:
1071                         {
1072                                 ObjectID resultId = insn.word(2);
1073                                 auto &object = getObject(resultId);
1074                                 auto &objectTy = getType(object.type);
1075                                 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
1076                                 {
1077                                         auto &dst = routine->getValue(resultId);
1078                                         int offset = 0;
1079                                         VisitInterface(resultId,
1080                                                                    [&](Decorations const &d, AttribType type) {
1081                                                                            auto scalarSlot = d.Location << 2 | d.Component;
1082                                                                            routine->outputs[scalarSlot] = dst[offset++];
1083                                                                    });
1084                                 }
1085                                 break;
1086                         }
1087                         default:
1088                                 break;
1089                         }
1090                 }
1091         }
1092 }