Android-x86
Fork
Donation

  • R/O
  • HTTP
  • SSH
  • HTTPS

external-swiftshader: Commit

external/swiftshader


Commit MetaInfo

Revision484e08e0fae627f107df3458242e158741a42e96 (tree)
Time2019-04-06 02:09:36
AuthorBen Clayton <bclayton@goog...>
CommiterBen Clayton

Log Message

SpirvShader: Rework pointer types

Previously Objects of the Variable kind would hold an Object::ID to another pointerBase object, which was combined with a per-lane offset in SpirvRoutine::intermediates.
This is almost exactly the same as PhysicalPointer - except the base address was taken from SpirvRoutine::physicalPointers.

With descriptor indices, we need a dynamic base pointer (only known at emit time) with per lane offsets.

This change transforms the Kind::Variable and Kind::PhysicalPointer kinds into Kind::DivergentPointer and Kind::NonDivergentPointer. This reduces complexity in loads and stores, and better represents the various forms of pointer we care about.

Bug: b/126330097
Change-Id: I514af5962b9cad4109197893066eda6f996be107
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28390
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>

Change Summary

Incremental Difference

--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -188,10 +188,9 @@ namespace sw
188188 UNIMPLEMENTED("Variable initializers not yet supported");
189189
190190 auto &object = defs[resultId];
191- object.kind = Object::Kind::Variable;
191+ object.kind = Object::Kind::NonDivergentPointer;
192192 object.definition = insn;
193193 object.type = typeId;
194- object.pointerBase = insn.word(2); // base is itself
195194
196195 ASSERT(getType(typeId).storageClass == storageClass);
197196
@@ -201,12 +200,10 @@ namespace sw
201200 case spv::StorageClassOutput:
202201 ProcessInterfaceVariable(object);
203202 break;
203+
204204 case spv::StorageClassUniform:
205205 case spv::StorageClassStorageBuffer:
206206 case spv::StorageClassPushConstant:
207- object.kind = Object::Kind::PhysicalPointer;
208- break;
209-
210207 case spv::StorageClassPrivate:
211208 case spv::StorageClassFunction:
212209 break; // Correctly handled.
@@ -438,23 +435,16 @@ namespace sw
438435 case spv::OpFwidthFine:
439436 case spv::OpAtomicLoad:
440437 case spv::OpPhi:
441- // Instructions that yield an intermediate value
438+ // Instructions that yield an intermediate value or divergent
439+ // pointer
442440 {
443441 Type::ID typeId = insn.word(1);
444442 Object::ID resultId = insn.word(2);
445443 auto &object = defs[resultId];
446444 object.type = typeId;
447- object.kind = Object::Kind::Intermediate;
445+ object.kind = (getType(typeId).opcode() == spv::OpTypePointer)
446+ ? Object::Kind::DivergentPointer : Object::Kind::Intermediate;
448447 object.definition = insn;
449-
450- if (insn.opcode() == spv::OpAccessChain || insn.opcode() == spv::OpInBoundsAccessChain)
451- {
452- // interior ptr has two parts:
453- // - logical base ptr, common across all lanes and known at compile time
454- // - per-lane offset
455- Object::ID baseId = insn.word(3);
456- object.pointerBase = getObject(baseId).pointerBase;
457- }
458448 break;
459449 }
460450
@@ -816,23 +806,38 @@ namespace sw
816806 VisitInterfaceInner<F>(def.word(1), d, f);
817807 }
818808
819- SIMD::Int SpirvShader::WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
809+ std::pair<Pointer<Byte>, SIMD::Int> SpirvShader::GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const
810+ {
811+ auto &object = getObject(id);
812+ switch (object.kind)
813+ {
814+ case Object::Kind::NonDivergentPointer:
815+ case Object::Kind::InterfaceVariable:
816+ return std::make_pair(routine->getPointer(id), SIMD::Int(0));
817+
818+ case Object::Kind::DivergentPointer:
819+ return std::make_pair(routine->getPointer(id), routine->getIntermediate(id).Int(0));
820+
821+ default:
822+ UNREACHABLE("Invalid pointer kind %d", int(object.kind));
823+ return std::make_pair(Pointer<Byte>(), SIMD::Int(0));
824+ }
825+ }
826+
827+ std::pair<Pointer<Byte>, SIMD::Int> SpirvShader::WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
820828 {
821829 // Produce a offset into external memory in sizeof(float) units
822830
823- int constantOffset = 0;
824- SIMD::Int dynamicOffset = SIMD::Int(0);
825831 auto &baseObject = getObject(id);
826832 Type::ID typeId = getType(baseObject.type).element;
827- Decorations d{};
833+ Decorations d = {};
828834 ApplyDecorationsForId(&d, baseObject.type);
829835
830- // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
831- // Start with its offset and build from there.
832- if (baseObject.kind == Object::Kind::Intermediate)
833- {
834- dynamicOffset += routine->getIntermediate(id).Int(0);
835- }
836+ SIMD::Int dynamicOffset;
837+ Pointer<Byte> pointerBase;
838+ std::tie(pointerBase, dynamicOffset) = GetPointerToData(id, 0, routine);
839+
840+ int constantOffset = 0;
836841
837842 for (auto i = 0u; i < numIndexes; i++)
838843 {
@@ -890,7 +895,7 @@ namespace sw
890895 }
891896 }
892897
893- return dynamicOffset + SIMD::Int(constantOffset);
898+ return std::make_pair(pointerBase, dynamicOffset + SIMD::Int(constantOffset));
894899 }
895900
896901 SIMD::Int SpirvShader::WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
@@ -903,9 +908,9 @@ namespace sw
903908 auto &baseObject = getObject(id);
904909 Type::ID typeId = getType(baseObject.type).element;
905910
906- // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
911+ // The <base> operand is a divergent pointer itself.
907912 // Start with its offset and build from there.
908- if (baseObject.kind == Object::Kind::Intermediate)
913+ if (baseObject.kind == Object::Kind::DivergentPointer)
909914 {
910915 dynamicOffset += routine->getIntermediate(id).Int(0);
911916 }
@@ -1699,8 +1704,16 @@ namespace sw
16991704 Object::ID resultId = insn.word(2);
17001705 auto &object = getObject(resultId);
17011706 auto &objectTy = getType(object.type);
1707+
17021708 switch (objectTy.storageClass)
17031709 {
1710+ case spv::StorageClassOutput:
1711+ case spv::StorageClassPrivate:
1712+ case spv::StorageClassFunction:
1713+ {
1714+ routine->createPointer(resultId, &routine->getVariable(resultId)[0]);
1715+ break;
1716+ }
17041717 case spv::StorageClassInput:
17051718 {
17061719 if (object.kind == Object::Kind::InterfaceVariable)
@@ -1713,6 +1726,7 @@ namespace sw
17131726 dst[offset++] = routine->inputs[scalarSlot];
17141727 });
17151728 }
1729+ routine->createPointer(resultId, &routine->getVariable(resultId)[0]);
17161730 break;
17171731 }
17181732 case spv::StorageClassUniform:
@@ -1741,12 +1755,12 @@ namespace sw
17411755 offset += routine->descriptorDynamicOffsets[dynamicBindingIndex];
17421756 }
17431757
1744- routine->physicalPointers[resultId] = data + offset;
1758+ routine->createPointer(resultId, data + offset);
17451759 break;
17461760 }
17471761 case spv::StorageClassPushConstant:
17481762 {
1749- routine->physicalPointers[resultId] = routine->pushConstants;
1763+ routine->createPointer(resultId, routine->pushConstants);
17501764 break;
17511765 }
17521766 default:
@@ -1765,8 +1779,7 @@ namespace sw
17651779 auto &result = getObject(resultId);
17661780 auto &resultTy = getType(result.type);
17671781 auto &pointer = getObject(pointerId);
1768- auto &pointerBase = getObject(pointer.pointerBase);
1769- auto &pointerBaseTy = getType(pointerBase.type);
1782+ auto &pointerTy = getType(pointer.type);
17701783 std::memory_order memoryOrder = std::memory_order_relaxed;
17711784
17721785 if(atomic)
@@ -1780,32 +1793,23 @@ namespace sw
17801793 ASSERT(Type::ID(insn.word(1)) == result.type);
17811794 ASSERT(!atomic || getType(getType(pointer.type).element).opcode() == spv::OpTypeInt); // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer."
17821795
1783- if (pointerBaseTy.storageClass == spv::StorageClassImage)
1796+ if (pointerTy.storageClass == spv::StorageClassImage)
17841797 {
17851798 UNIMPLEMENTED("StorageClassImage load not yet implemented");
17861799 }
17871800
1801+ SIMD::Int offsets;
17881802 Pointer<Float> ptrBase;
1789- if (pointerBase.kind == Object::Kind::PhysicalPointer)
1790- {
1791- ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1792- }
1793- else
1794- {
1795- ptrBase = &routine->getVariable(pointer.pointerBase)[0];
1796- }
1803+ std::tie(ptrBase, offsets) = GetPointerToData(pointerId, 0, routine);
17971804
1798- bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
1805+ bool interleavedByLane = IsStorageInterleavedByLane(pointerTy.storageClass);
17991806 auto anyInactiveLanes = AnyFalse(state->activeLaneMask());
18001807
18011808 auto load = std::unique_ptr<SIMD::Float[]>(new SIMD::Float[resultTy.sizeInComponents]);
18021809
1803- If(pointer.kind == Object::Kind::Intermediate || anyInactiveLanes)
1810+ If(pointer.kind == Object::Kind::DivergentPointer || anyInactiveLanes)
18041811 {
18051812 // Divergent offsets or masked lanes.
1806- auto offsets = pointer.kind == Object::Kind::Intermediate ?
1807- As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1808- RValue<SIMD::Int>(SIMD::Int(0));
18091813 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
18101814 {
18111815 // i wish i had a Float,Float,Float,Float constructor here..
@@ -1861,8 +1865,6 @@ namespace sw
18611865 auto &pointer = getObject(pointerId);
18621866 auto &pointerTy = getType(pointer.type);
18631867 auto &elementTy = getType(pointerTy.element);
1864- auto &pointerBase = getObject(pointer.pointerBase);
1865- auto &pointerBaseTy = getType(pointerBase.type);
18661868 std::memory_order memoryOrder = std::memory_order_relaxed;
18671869
18681870 if(atomic)
@@ -1874,34 +1876,26 @@ namespace sw
18741876
18751877 ASSERT(!atomic || elementTy.opcode() == spv::OpTypeInt); // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer."
18761878
1877- if (pointerBaseTy.storageClass == spv::StorageClassImage)
1879+ if (pointerTy.storageClass == spv::StorageClassImage)
18781880 {
18791881 UNIMPLEMENTED("StorageClassImage store not yet implemented");
18801882 }
18811883
1884+ SIMD::Int offsets;
18821885 Pointer<Float> ptrBase;
1883- if (pointerBase.kind == Object::Kind::PhysicalPointer)
1884- {
1885- ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1886- }
1887- else
1888- {
1889- ptrBase = &routine->getVariable(pointer.pointerBase)[0];
1890- }
1886+ std::tie(ptrBase, offsets) = GetPointerToData(pointerId, 0, routine);
18911887
1892- bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
1888+ bool interleavedByLane = IsStorageInterleavedByLane(pointerTy.storageClass);
18931889 auto anyInactiveLanes = AnyFalse(state->activeLaneMask());
18941890
18951891 if (object.kind == Object::Kind::Constant)
18961892 {
18971893 // Constant source data.
18981894 auto src = reinterpret_cast<float *>(object.constantValue.get());
1899- If(pointer.kind == Object::Kind::Intermediate || anyInactiveLanes)
1895+ If(pointer.kind == Object::Kind::DivergentPointer || anyInactiveLanes)
19001896 {
19011897 // Divergent offsets or masked lanes.
1902- auto offsets = pointer.kind == Object::Kind::Intermediate ?
1903- As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1904- RValue<SIMD::Int>(SIMD::Int(0));
1898+
19051899 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
19061900 {
19071901 for (int j = 0; j < SIMD::Width; j++)
@@ -1930,12 +1924,9 @@ namespace sw
19301924 {
19311925 // Intermediate source data.
19321926 auto &src = routine->getIntermediate(objectId);
1933- If(pointer.kind == Object::Kind::Intermediate || anyInactiveLanes)
1927+ If(pointer.kind == Object::Kind::DivergentPointer || anyInactiveLanes)
19341928 {
19351929 // Divergent offsets or masked lanes.
1936- auto offsets = pointer.kind == Object::Kind::Intermediate ?
1937- As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1938- RValue<SIMD::Int>(SIMD::Int(0));
19391930 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
19401931 {
19411932 for (int j = 0; j < SIMD::Width; j++)
@@ -1986,19 +1977,21 @@ namespace sw
19861977 const uint32_t *indexes = insn.wordPointer(4);
19871978 auto &type = getType(typeId);
19881979 ASSERT(type.sizeInComponents == 1);
1989- ASSERT(getObject(baseId).pointerBase == getObject(resultId).pointerBase);
1990-
1991- auto &dst = routine->createIntermediate(resultId, type.sizeInComponents);
1980+ ASSERT(getObject(resultId).kind == Object::Kind::DivergentPointer);
19921981
19931982 if(type.storageClass == spv::StorageClassPushConstant ||
19941983 type.storageClass == spv::StorageClassUniform ||
19951984 type.storageClass == spv::StorageClassStorageBuffer)
19961985 {
1997- dst.move(0, WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine));
1986+ auto baseAndOffset = WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine);
1987+ routine->createPointer(resultId, baseAndOffset.first);
1988+ routine->createIntermediate(resultId, type.sizeInComponents).move(0, baseAndOffset.second);
19981989 }
19991990 else
20001991 {
2001- dst.move(0, WalkAccessChain(baseId, numIndexes, indexes, routine));
1992+ auto offset = WalkAccessChain(baseId, numIndexes, indexes, routine);
1993+ routine->createPointer(resultId, routine->getPointer(baseId));
1994+ routine->createIntermediate(resultId, type.sizeInComponents).move(0, offset);
20021995 }
20031996
20041997 return EmitResult::Continue;
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -233,17 +233,36 @@ namespace sw
233233
234234 InsnIterator definition;
235235 Type::ID type;
236- ID pointerBase;
237236 std::unique_ptr<uint32_t[]> constantValue = nullptr;
238237
239238 enum class Kind
240239 {
241- Unknown, /* for paranoia -- if we get left with an object in this state, the module was broken */
242- Variable, // TODO: Document
243- InterfaceVariable, // TODO: Document
244- Constant, // Values held by Object::constantValue
245- Intermediate, // Values held by SpirvRoutine::intermediates
246- PhysicalPointer, // Pointer held by SpirvRoutine::physicalPointers
240+ // Invalid default kind.
241+ // If we get left with an object in this state, the module was
242+ // broken.
243+ Unknown,
244+
245+ // TODO: Better document this kind.
246+ // A shader interface variable pointer.
247+ // Pointer with uniform address across all lanes.
248+ // Pointer held by SpirvRoutine::pointers
249+ InterfaceVariable,
250+
251+ // Constant value held by Object::constantValue.
252+ Constant,
253+
254+ // Value held by SpirvRoutine::intermediates.
255+ Intermediate,
256+
257+ // DivergentPointer formed from a base pointer and per-lane offset.
258+ // Base pointer held by SpirvRoutine::pointers
259+ // Per-lane offset held by SpirvRoutine::intermediates.
260+ DivergentPointer,
261+
262+ // Pointer with uniform address across all lanes.
263+ // Pointer held by SpirvRoutine::pointers
264+ NonDivergentPointer,
265+
247266 } kind = Kind::Unknown;
248267 };
249268
@@ -539,7 +558,15 @@ namespace sw
539558
540559 void ProcessInterfaceVariable(Object &object);
541560
542- SIMD::Int WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
561+ // Returns a base pointer and per-lane offset to the underlying data for
562+ // the given pointer object. Handles objects of the following kinds:
563+ // • DivergentPointer
564+ // • InterfaceVariable
565+ // • NonDivergentPointer
566+ // Calling GetPointerToData with objects of any other kind will assert.
567+ std::pair<Pointer<Byte>, SIMD::Int> GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const;
568+
569+ std::pair<Pointer<Byte>, SIMD::Int> WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
543570 SIMD::Int WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
544571 uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const;
545572
@@ -655,7 +682,7 @@ namespace sw
655682
656683 std::unordered_map<SpirvShader::Object::ID, Intermediate> intermediates;
657684
658- std::unordered_map<SpirvShader::Object::ID, Pointer<Byte> > physicalPointers;
685+ std::unordered_map<SpirvShader::Object::ID, Pointer<Byte> > pointers;
659686
660687 Variable inputs = Variable{MAX_INTERFACE_COMPONENTS};
661688 Variable outputs = Variable{MAX_INTERFACE_COMPONENTS};
@@ -671,6 +698,25 @@ namespace sw
671698 ASSERT_MSG(added, "Variable %d created twice", id.value());
672699 }
673700
701+ template <typename T>
702+ void createPointer(SpirvShader::Object::ID id, Pointer<T> ptrBase)
703+ {
704+ bool added = pointers.emplace(id, ptrBase).second;
705+ ASSERT_MSG(added, "Pointer %d created twice", id.value());
706+ }
707+
708+ template <typename T>
709+ void createPointer(SpirvShader::Object::ID id, RValue<Pointer<T>> ptrBase)
710+ {
711+ createPointer(id, Pointer<T>(ptrBase));
712+ }
713+
714+ template <typename T>
715+ void createPointer(SpirvShader::Object::ID id, Reference<Pointer<T>> ptrBase)
716+ {
717+ createPointer(id, Pointer<T>(ptrBase));
718+ }
719+
674720 Intermediate& createIntermediate(SpirvShader::Object::ID id, uint32_t size)
675721 {
676722 auto it = intermediates.emplace(std::piecewise_construct,
@@ -694,10 +740,10 @@ namespace sw
694740 return it->second;
695741 }
696742
697- Pointer<Byte>& getPhysicalPointer(SpirvShader::Object::ID id)
743+ Pointer<Byte>& getPointer(SpirvShader::Object::ID id)
698744 {
699- auto it = physicalPointers.find(id);
700- ASSERT_MSG(it != physicalPointers.end(), "Unknown physical pointer %d", id.value());
745+ auto it = pointers.find(id);
746+ ASSERT_MSG(it != pointers.end(), "Unknown pointer %d", id.value());
701747 return it->second;
702748 }
703749 };
Show on old repository browser