1 // Copyright 2018 The SwiftShader Authors. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
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"
23 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
25 SpirvShader::SpirvShader(InsnStore const &insns)
26 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
27 outputs{MAX_INTERFACE_COMPONENTS},
28 serialID{serialCounter++}, modes{}
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
34 for (auto insn : *this)
36 switch (insn.opcode())
38 case spv::OpExecutionMode:
39 ProcessExecutionMode(insn);
44 auto targetId = insn.word(1);
45 auto decoration = static_cast<spv::Decoration>(insn.word(2));
46 decorations[targetId].Apply(
48 insn.wordCount() > 3 ? insn.word(3) : 0);
50 if (decoration == spv::DecorationCentroid)
51 modes.NeedsCentroid = true;
55 case spv::OpMemberDecorate:
57 auto 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));
65 insn.wordCount() > 4 ? insn.word(4) : 0);
67 if (decoration == spv::DecorationCentroid)
68 modes.NeedsCentroid = true;
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.
78 case spv::OpGroupDecorate:
80 auto const &srcDecorations = decorations[insn.word(1)];
81 for (auto i = 2u; i < insn.wordCount(); i++)
83 // remaining operands are targets to apply the group to.
84 decorations[insn.word(i)].Apply(srcDecorations);
89 case spv::OpGroupMemberDecorate:
91 auto const &srcDecorations = decorations[insn.word(1)];
92 for (auto i = 2u; i < insn.wordCount(); i += 2)
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);
104 case spv::OpTypeVoid:
105 case spv::OpTypeBool:
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:
119 auto resultId = insn.word(1);
120 auto &object = types[resultId];
121 object.kind = Object::Kind::Type;
122 object.definition = insn;
123 object.sizeInComponents = ComputeTypeSize(insn);
125 // A structure is a builtin block if it has a builtin
126 // member. All members of such a structure are builtins.
127 if (insn.opcode() == spv::OpTypeStruct)
129 auto d = memberDecorations.find(resultId);
130 if (d != memberDecorations.end())
132 for (auto &m : d->second)
136 object.isBuiltInBlock = true;
142 else if (insn.opcode() == spv::OpTypePointer)
144 auto pointeeType = insn.word(3);
145 object.isBuiltInBlock = getType(pointeeType).isBuiltInBlock;
150 case spv::OpVariable:
152 auto typeId = insn.word(1);
153 auto resultId = insn.word(2);
154 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
155 if (insn.wordCount() > 4)
156 UNIMPLEMENTED("Variable initializers not yet supported");
158 auto &object = defs[resultId];
159 object.kind = Object::Kind::Variable;
160 object.definition = insn;
161 object.storageClass = storageClass;
163 auto &type = getType(typeId);
164 auto &pointeeType = getType(type.definition.word(3));
166 // OpVariable's "size" is the size of the allocation required (the size of the pointee)
167 object.sizeInComponents = pointeeType.sizeInComponents;
168 object.isBuiltInBlock = type.isBuiltInBlock;
169 object.pointerBase = insn.word(2); // base is itself
173 if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput)
175 ProcessInterfaceVariable(object);
180 case spv::OpConstant:
181 case spv::OpConstantComposite:
182 case spv::OpConstantFalse:
183 case spv::OpConstantTrue:
184 case spv::OpConstantNull:
186 auto typeId = insn.word(1);
187 auto resultId = insn.word(2);
188 auto &object = defs[resultId];
189 object.kind = Object::Kind::Constant;
190 object.definition = insn;
191 object.sizeInComponents = getType(typeId).sizeInComponents;
195 case spv::OpCapability:
196 // Various capabilities will be declared, but none affect our code generation at this point.
197 case spv::OpMemoryModel:
198 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
199 case spv::OpEntryPoint:
200 case spv::OpFunction:
201 case spv::OpFunctionEnd:
202 // Due to preprocessing, the entrypoint and its function provide no value.
204 case spv::OpExtInstImport:
205 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
206 // Valid shaders will not attempt to import any other instruction sets.
209 case spv::OpFunctionParameter:
210 case spv::OpFunctionCall:
211 case spv::OpSpecConstant:
212 case spv::OpSpecConstantComposite:
213 case spv::OpSpecConstantFalse:
214 case spv::OpSpecConstantOp:
215 case spv::OpSpecConstantTrue:
216 // These should have all been removed by preprocessing passes. If we see them here,
217 // our assumptions are wrong and we will probably generate wrong code.
218 UNIMPLEMENTED("These instructions should have already been lowered.");
222 case spv::OpAccessChain:
223 // Instructions that yield an ssavalue.
225 auto typeId = insn.word(1);
226 auto resultId = insn.word(2);
227 auto &object = defs[resultId];
228 object.kind = Object::Kind::Value;
229 object.definition = insn;
230 object.sizeInComponents = getType(typeId).sizeInComponents;
232 if (insn.opcode() == spv::OpAccessChain)
234 // interior ptr has two parts:
235 // - logical base ptr, common across all lanes and known at compile time
237 object.pointerBase = getObject(insn.word(3)).pointerBase;
244 // Don't need to do anything during analysis pass
248 modes.ContainsKill = true;
252 printf("Warning: ignored opcode %u\n", insn.opcode());
253 break; // This is OK, these passes are intentionally partial
258 void SpirvShader::ProcessInterfaceVariable(Object &object)
260 assert(object.storageClass == spv::StorageClassInput || object.storageClass == spv::StorageClassOutput);
262 auto &builtinInterface = (object.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
263 auto &userDefinedInterface = (object.storageClass == spv::StorageClassInput) ? inputs : outputs;
265 auto resultId = object.definition.word(2);
266 if (object.isBuiltInBlock)
268 // walk the builtin block, registering each of its members separately.
269 auto ptrType = getType(object.definition.word(1)).definition;
270 assert(ptrType.opcode() == spv::OpTypePointer);
271 auto pointeeType = ptrType.word(3);
272 auto m = memberDecorations.find(pointeeType);
273 assert(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
274 auto &structType = getType(pointeeType).definition;
277 for (auto &member : m->second)
279 auto &memberType = getType(structType.word(word));
281 if (member.HasBuiltIn)
283 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
286 offset += memberType.sizeInComponents;
292 auto d = decorations.find(resultId);
293 if (d != decorations.end() && d->second.HasBuiltIn)
295 builtinInterface[d->second.BuiltIn] = {resultId, 0, object.sizeInComponents};
299 object.kind = Object::Kind::InterfaceVariable;
300 VisitInterface(resultId,
301 [&userDefinedInterface](Decorations const &d, AttribType type) {
302 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
303 auto scalarSlot = (d.Location << 2) | d.Component;
304 assert(scalarSlot >= 0 &&
305 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
307 auto &slot = userDefinedInterface[scalarSlot];
310 slot.NoPerspective = d.NoPerspective;
311 slot.Centroid = d.Centroid;
316 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
318 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
321 case spv::ExecutionModeEarlyFragmentTests:
322 modes.EarlyFragmentTests = true;
324 case spv::ExecutionModeDepthReplacing:
325 modes.DepthReplacing = true;
327 case spv::ExecutionModeDepthGreater:
328 modes.DepthGreater = true;
330 case spv::ExecutionModeDepthLess:
331 modes.DepthLess = true;
333 case spv::ExecutionModeDepthUnchanged:
334 modes.DepthUnchanged = true;
336 case spv::ExecutionModeLocalSize:
337 modes.LocalSizeX = insn.word(3);
338 modes.LocalSizeZ = insn.word(5);
339 modes.LocalSizeY = insn.word(4);
341 case spv::ExecutionModeOriginUpperLeft:
342 // This is always the case for a Vulkan shader. Do nothing.
345 UNIMPLEMENTED("No other execution modes are permitted");
349 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
351 // Types are always built from the bottom up (with the exception of forward ptrs, which
352 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
353 // already been described (and so their sizes determined)
354 switch (insn.opcode())
356 case spv::OpTypeVoid:
357 case spv::OpTypeSampler:
358 case spv::OpTypeImage:
359 case spv::OpTypeSampledImage:
360 case spv::OpTypeFunction:
361 case spv::OpTypeRuntimeArray:
362 // Objects that don't consume any space.
363 // Descriptor-backed objects currently only need exist at compile-time.
364 // Runtime arrays don't appear in places where their size would be interesting
367 case spv::OpTypeBool:
368 case spv::OpTypeFloat:
370 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
371 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
374 case spv::OpTypeVector:
375 case spv::OpTypeMatrix:
376 // Vectors and matrices both consume element count * element size.
377 return getType(insn.word(2)).sizeInComponents * insn.word(3);
379 case spv::OpTypeArray:
381 // Element count * element size. Array sizes come from constant ids.
382 auto arraySize = GetConstantInt(insn.word(3));
383 return getType(insn.word(2)).sizeInComponents * arraySize;
386 case spv::OpTypeStruct:
389 for (uint32_t i = 2u; i < insn.wordCount(); i++)
391 size += getType(insn.word(i)).sizeInComponents;
396 case spv::OpTypePointer:
397 // Runtime representation of a pointer is a per-lane index.
398 // Note: clients are expected to look through the pointer if they want the pointee size instead.
402 // Some other random insn.
403 UNIMPLEMENTED("Only types are supported");
408 int SpirvShader::VisitInterfaceInner(uint32_t id, Decorations d, F f) const
410 // Recursively walks variable definition and its type tree, taking into account
411 // any explicit Location or Component decorations encountered; where explicit
412 // Locations or Components are not specified, assigns them sequentially.
413 // Collected decorations are carried down toward the leaves and across
414 // siblings; Effect of decorations intentionally does not flow back up the tree.
416 // F is a functor to be called with the effective decoration set for every component.
418 // Returns the next available location, and calls f().
420 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
422 ApplyDecorationsForId(&d, id);
424 auto const &obj = getType(id);
425 switch (obj.definition.opcode())
427 case spv::OpTypePointer:
428 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
429 case spv::OpTypeMatrix:
430 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
432 // consumes same components of N consecutive locations
433 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
436 case spv::OpTypeVector:
437 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
439 // consumes N consecutive components in the same location
440 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
442 return d.Location + 1;
443 case spv::OpTypeFloat:
444 f(d, ATTRIBTYPE_FLOAT);
445 return d.Location + 1;
447 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
448 return d.Location + 1;
449 case spv::OpTypeBool:
450 f(d, ATTRIBTYPE_UINT);
451 return d.Location + 1;
452 case spv::OpTypeStruct:
454 // iterate over members, which may themselves have Location/Component decorations
455 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
457 ApplyDecorationsForIdMember(&d, id, i);
458 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
459 d.Component = 0; // Implicit locations always have component=0
463 case spv::OpTypeArray:
465 auto arraySize = GetConstantInt(obj.definition.word(3));
466 for (auto i = 0u; i < arraySize; i++)
468 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
473 // Intentionally partial; most opcodes do not participate in type hierarchies
479 void SpirvShader::VisitInterface(uint32_t id, F f) const
481 // Walk a variable definition and call f for each component in it.
483 ApplyDecorationsForId(&d, id);
485 auto def = getObject(id).definition;
486 assert(def.opcode() == spv::OpVariable);
487 VisitInterfaceInner<F>(def.word(1), d, f);
490 Int4 SpirvShader::WalkAccessChain(uint32_t id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
492 // TODO: think about decorations, to make this work on location based interfaces
493 // TODO: think about explicit layout (UBO/SSBO) storage classes
494 // TODO: avoid doing per-lane work in some cases if we can?
497 auto & baseObject = getObject(id);
498 auto typeId = baseObject.definition.word(1);
500 if (baseObject.kind == Object::Kind::Value)
501 res += As<Int4>((*routine->lvalues[id])[0]);
503 for (auto i = 0u; i < numIndexes; i++)
505 auto & type = getType(typeId);
506 switch (type.definition.opcode())
508 case spv::OpTypeStruct:
510 int memberIndex = GetConstantInt(indexIds[i]);
511 int offsetIntoStruct = 0;
512 for (auto j = 0; j < memberIndex; j++) {
513 offsetIntoStruct += getType(type.definition.word(2 + memberIndex)).sizeInComponents;
515 res += Int4(offsetIntoStruct);
519 case spv::OpTypeVector:
520 case spv::OpTypeMatrix:
521 case spv::OpTypeArray:
523 auto stride = getType(type.definition.word(2)).sizeInComponents;
524 auto & obj = getObject(indexIds[i]);
525 if (obj.kind == Object::Kind::Constant)
526 res += Int4(stride * GetConstantInt(indexIds[i]));
528 res += Int4(stride) * As<Int4>((*(routine->lvalues)[indexIds[i]])[0]);
533 UNIMPLEMENTED("Unexpected type in WalkAccessChain");
540 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
544 case spv::DecorationLocation:
546 Location = static_cast<int32_t>(arg);
548 case spv::DecorationComponent:
552 case spv::DecorationBuiltIn:
554 BuiltIn = static_cast<spv::BuiltIn>(arg);
556 case spv::DecorationFlat:
559 case spv::DecorationNoPerspective:
560 NoPerspective = true;
562 case spv::DecorationCentroid:
565 case spv::DecorationBlock:
568 case spv::DecorationBufferBlock:
572 // Intentionally partial, there are many decorations we just don't care about.
577 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
579 // Apply a decoration group to this set of decorations
583 BuiltIn = src.BuiltIn;
589 Location = src.Location;
592 if (src.HasComponent)
595 Component = src.Component;
599 NoPerspective |= src.NoPerspective;
600 Centroid |= src.Centroid;
602 BufferBlock |= src.BufferBlock;
605 void SpirvShader::ApplyDecorationsForId(Decorations *d, uint32_t id) const
607 auto it = decorations.find(id);
608 if (it != decorations.end())
609 d->Apply(it->second);
612 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, uint32_t id, uint32_t member) const
614 auto it = memberDecorations.find(id);
615 if (it != memberDecorations.end() && member < it->second.size())
617 d->Apply(it->second[member]);
621 uint32_t SpirvShader::GetConstantInt(uint32_t id) const
623 // Slightly hackish access to constants very early in translation.
624 // General consumption of constants by other instructions should
625 // probably be just lowered to Reactor.
627 // TODO: not encountered yet since we only use this for array sizes etc,
628 // but is possible to construct integer constant 0 via OpConstantNull.
629 auto insn = getObject(id).definition;
630 assert(insn.opcode() == spv::OpConstant);
631 assert(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
637 void SpirvShader::emitEarly(SpirvRoutine *routine) const
639 for (auto insn : *this)
641 switch (insn.opcode())
643 case spv::OpVariable:
645 auto &object = getObject(insn.word(2));
646 // Want to exclude: location-oriented interface variables; special things that consume zero slots.
647 // TODO: what to do about zero-slot objects?
648 if (object.kind != Object::Kind::InterfaceVariable && object.sizeInComponents > 0)
650 // any variable not in a location-oriented interface
651 routine->createLvalue(insn.word(2), object.sizeInComponents);
656 // Nothing else produces interface variables, so can all be safely ignored.
662 void SpirvShader::emit(SpirvRoutine *routine) const
664 for (auto insn : *this)
666 switch (insn.opcode())
670 auto &object = getObject(insn.word(2));
671 auto &type = getType(insn.word(1));
672 auto &pointer = getObject(insn.word(3));
673 routine->createLvalue(insn.word(2), type.sizeInComponents); // TODO: this should be an ssavalue!
674 auto &pointerBase = getObject(pointer.pointerBase);
676 if (pointerBase.kind == Object::Kind::InterfaceVariable)
678 UNIMPLEMENTED("Location-based load not yet implemented");
681 if (pointerBase.storageClass == spv::StorageClassImage ||
682 pointerBase.storageClass == spv::StorageClassUniform ||
683 pointerBase.storageClass == spv::StorageClassUniformConstant)
685 UNIMPLEMENTED("Descriptor-backed load not yet implemented");
688 SpirvRoutine::Value& ptrBase = *(routine->lvalues)[pointer.pointerBase];
689 auto & dst = *(routine->lvalues)[insn.word(2)];
691 if (pointer.kind == Object::Kind::Value)
693 auto offsets = As<Int4>(*(routine->lvalues)[insn.word(3)]);
694 for (auto i = 0u; i < object.sizeInComponents; i++)
696 // i wish i had a Float,Float,Float,Float constructor here..
698 for (int j = 0; j < 4; j++)
699 v = Insert(v, Extract(ptrBase[Int(i) + Extract(offsets, j)], j), j);
705 // no divergent offsets to worry about
706 for (auto i = 0u; i < object.sizeInComponents; i++)
713 case spv::OpAccessChain:
715 auto &object = getObject(insn.word(2));
716 auto &type = getType(insn.word(1));
717 auto &base = getObject(insn.word(3));
718 routine->createLvalue(insn.word(2), type.sizeInComponents); // TODO: this should be an ssavalue!
719 auto &pointerBase = getObject(object.pointerBase);
720 assert(type.sizeInComponents == 1);
721 assert(base.pointerBase == object.pointerBase);
723 if (pointerBase.kind == Object::Kind::InterfaceVariable)
725 UNIMPLEMENTED("Location-based OpAccessChain not yet implemented");
728 if (pointerBase.storageClass == spv::StorageClassImage ||
729 pointerBase.storageClass == spv::StorageClassUniform ||
730 pointerBase.storageClass == spv::StorageClassUniformConstant)
732 UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
735 auto & dst = *(routine->lvalues)[insn.word(2)];
736 dst[0] = As<Float4>(WalkAccessChain(insn.word(3), insn.wordCount() - 4, insn.wordPointer(4), routine));
741 auto &object = getObject(insn.word(2));
742 auto &pointer = getObject(insn.word(1));
743 auto &pointerBase = getObject(pointer.pointerBase);
745 if (pointerBase.kind == Object::Kind::InterfaceVariable)
747 UNIMPLEMENTED("Location-based store not yet implemented");
750 if (pointerBase.storageClass == spv::StorageClassImage ||
751 pointerBase.storageClass == spv::StorageClassUniform ||
752 pointerBase.storageClass == spv::StorageClassUniformConstant)
754 UNIMPLEMENTED("Descriptor-backed store not yet implemented");
757 SpirvRoutine::Value& ptrBase = *(routine->lvalues)[pointer.pointerBase];
758 auto & src = *(routine->lvalues)[insn.word(2)];
760 if (pointer.kind == Object::Kind::Value)
762 auto offsets = As<Int4>(*(routine->lvalues)[insn.word(1)]);
763 for (auto i = 0u; i < object.sizeInComponents; i++)
766 for (int j = 0; j < 4; j++)
768 auto dst = ptrBase[Int(i) + Extract(offsets, j)];
769 dst = Insert(dst, Extract(src[i], j), j);
775 // no divergent offsets
776 for (auto i = 0u; i < object.sizeInComponents; i++)
784 printf("emit: ignoring opcode %d\n", insn.opcode());