Commit 831db96b by Ben Clayton

SpirvShader: Add PhysicalPointers

And add load / store paths to deal with data layouts that are not interleaved by lane. Bug: b/126330097 Change-Id: Id7730a606d623ffe74ae57668216f05159972f10 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/25710Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent a2a00e21
...@@ -542,6 +542,18 @@ namespace sw ...@@ -542,6 +542,18 @@ namespace sw
} }
} }
bool SpirvShader::IsStorageInterleavedByLane(spv::StorageClass storageClass)
{
switch (storageClass)
{
case spv::StorageClassUniform:
case spv::StorageClassStorageBuffer:
return false;
default:
return true;
}
}
template<typename F> template<typename F>
int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
{ {
...@@ -1056,12 +1068,24 @@ namespace sw ...@@ -1056,12 +1068,24 @@ namespace sw
UNIMPLEMENTED("Descriptor-backed load not yet implemented"); UNIMPLEMENTED("Descriptor-backed load not yet implemented");
} }
auto &ptrBase = routine->getValue(pointer.pointerBase); Pointer<Float> ptrBase;
if (pointerBase.kind == Object::Kind::PhysicalPointer)
{
ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
}
else
{
ptrBase = &routine->getValue(pointer.pointerBase)[0];
}
bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents); auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
if (pointer.kind == Object::Kind::Value) if (pointer.kind == Object::Kind::Value)
{ {
auto offsets = As<SIMD::Int>(routine->getIntermediate(insn.word(3))[0]); // Divergent offsets.
auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
for (auto i = 0u; i < objectTy.sizeInComponents; i++) for (auto i = 0u; i < objectTy.sizeInComponents; i++)
{ {
// i wish i had a Float,Float,Float,Float constructor here.. // i wish i had a Float,Float,Float,Float constructor here..
...@@ -1069,17 +1093,27 @@ namespace sw ...@@ -1069,17 +1093,27 @@ namespace sw
for (int j = 0; j < SIMD::Width; j++) for (int j = 0; j < SIMD::Width; j++)
{ {
Int offset = Int(i) + Extract(offsets, j); Int offset = Int(i) + Extract(offsets, j);
v = Insert(v, Extract(ptrBase[offset], j), j); if (interleavedByLane) { offset = offset * SIMD::Width + j; }
v = Insert(v, ptrBase[offset], j);
} }
dst.emplace(i, v); dst.emplace(i, v);
} }
} }
else if (interleavedByLane)
{
// Lane-interleaved data. No divergent offsets.
Pointer<SIMD::Float> src = ptrBase;
for (auto i = 0u; i < objectTy.sizeInComponents; i++)
{
dst.emplace(i, src[i]);
}
}
else else
{ {
// no divergent offsets to worry about // Non-interleaved data. No divergent offsets.
for (auto i = 0u; i < objectTy.sizeInComponents; i++) for (auto i = 0u; i < objectTy.sizeInComponents; i++)
{ {
dst.emplace(i, ptrBase[i]); dst.emplace(i, RValue<SIMD::Float>(ptrBase[i]));
} }
} }
} }
...@@ -1124,7 +1158,17 @@ namespace sw ...@@ -1124,7 +1158,17 @@ namespace sw
UNIMPLEMENTED("Descriptor-backed store not yet implemented"); UNIMPLEMENTED("Descriptor-backed store not yet implemented");
} }
auto &ptrBase = routine->getValue(pointer.pointerBase); Pointer<Float> ptrBase;
if (pointerBase.kind == Object::Kind::PhysicalPointer)
{
ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
}
else
{
ptrBase = &routine->getValue(pointer.pointerBase)[0];
}
bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
if (object.kind == Object::Kind::Constant) if (object.kind == Object::Kind::Constant)
{ {
...@@ -1132,23 +1176,25 @@ namespace sw ...@@ -1132,23 +1176,25 @@ namespace sw
if (pointer.kind == Object::Kind::Value) if (pointer.kind == Object::Kind::Value)
{ {
// Constant source data. Divergent offsets.
auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]); auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
for (auto i = 0u; i < elementTy.sizeInComponents; i++) for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{ {
// Scattered store
for (int j = 0; j < SIMD::Width; j++) for (int j = 0; j < SIMD::Width; j++)
{ {
auto dst = ptrBase[Int(i) + Extract(offsets, j)]; Int offset = Int(i) + Extract(offsets, j);
dst = Insert(dst, Float(src[i]), j); if (interleavedByLane) { offset = offset * SIMD::Width + j; }
ptrBase[offset] = RValue<Float>(src[i]);
} }
} }
} }
else else
{ {
// no divergent offsets // Constant source data. No divergent offsets.
Pointer<SIMD::Float> dst = ptrBase;
for (auto i = 0u; i < elementTy.sizeInComponents; i++) for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{ {
ptrBase[i] = RValue<SIMD::Float>(src[i]); dst[i] = RValue<SIMD::Float>(src[i]);
} }
} }
} }
...@@ -1158,23 +1204,34 @@ namespace sw ...@@ -1158,23 +1204,34 @@ namespace sw
if (pointer.kind == Object::Kind::Value) if (pointer.kind == Object::Kind::Value)
{ {
// Intermediate source data. Divergent offsets.
auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]); auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
for (auto i = 0u; i < elementTy.sizeInComponents; i++) for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{ {
// Scattered store
for (int j = 0; j < SIMD::Width; j++) for (int j = 0; j < SIMD::Width; j++)
{ {
auto dst = ptrBase[Int(i) + Extract(offsets, j)]; Int offset = Int(i) + Extract(offsets, j);
dst = Insert(dst, Extract(src[i], j), j); if (interleavedByLane) { offset = offset * SIMD::Width + j; }
ptrBase[offset] = Extract(src[i], j);
} }
} }
} }
else if (interleavedByLane)
{
// Intermediate source data. Lane-interleaved data. No divergent offsets.
Pointer<SIMD::Float> dst = ptrBase;
for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{
dst[i] = src[i];
}
}
else else
{ {
// no divergent offsets // Intermediate source data. Non-interleaved data. No divergent offsets.
Pointer<SIMD::Float> dst = ptrBase;
for (auto i = 0u; i < elementTy.sizeInComponents; i++) for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{ {
ptrBase[i] = src[i]; dst[i] = SIMD::Float(src[i]);
} }
} }
} }
......
...@@ -220,10 +220,11 @@ namespace sw ...@@ -220,10 +220,11 @@ namespace sw
enum class Kind enum class Kind
{ {
Unknown, /* for paranoia -- if we get left with an object in this state, the module was broken */ Unknown, /* for paranoia -- if we get left with an object in this state, the module was broken */
Variable, Variable, // TODO: Document
InterfaceVariable, InterfaceVariable, // TODO: Document
Constant, Constant, // Values held by Object::constantValue
Value, Value, // Values held by SpirvRoutine::intermediates
PhysicalPointer, // Pointer held by SpirvRoutine::physicalPointers
} kind = Kind::Unknown; } kind = Kind::Unknown;
}; };
...@@ -384,6 +385,34 @@ namespace sw ...@@ -384,6 +385,34 @@ namespace sw
void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const; void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const;
void ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const; void ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const;
// Returns true if data in the given storage class is word-interleaved
// by each SIMD vector lane, otherwise data is linerally stored.
//
// A 'lane' is a component of a SIMD vector register.
// Given 4 consecutive loads/stores of 4 SIMD vector registers:
//
// "StorageInterleavedByLane":
//
// Ptr+0:Reg0.x | Ptr+1:Reg0.y | Ptr+2:Reg0.z | Ptr+3:Reg0.w
// --------------+--------------+--------------+--------------
// Ptr+4:Reg1.x | Ptr+5:Reg1.y | Ptr+6:Reg1.z | Ptr+7:Reg1.w
// --------------+--------------+--------------+--------------
// Ptr+8:Reg2.x | Ptr+9:Reg2.y | Ptr+a:Reg2.z | Ptr+b:Reg2.w
// --------------+--------------+--------------+--------------
// Ptr+c:Reg3.x | Ptr+d:Reg3.y | Ptr+e:Reg3.z | Ptr+f:Reg3.w
//
// Not "StorageInterleavedByLane":
//
// Ptr+0:Reg0.x | Ptr+0:Reg0.y | Ptr+0:Reg0.z | Ptr+0:Reg0.w
// --------------+--------------+--------------+--------------
// Ptr+1:Reg1.x | Ptr+1:Reg1.y | Ptr+1:Reg1.z | Ptr+1:Reg1.w
// --------------+--------------+--------------+--------------
// Ptr+2:Reg2.x | Ptr+2:Reg2.y | Ptr+2:Reg2.z | Ptr+2:Reg2.w
// --------------+--------------+--------------+--------------
// Ptr+3:Reg3.x | Ptr+3:Reg3.y | Ptr+3:Reg3.z | Ptr+3:Reg3.w
//
static bool IsStorageInterleavedByLane(spv::StorageClass storageClass);
template<typename F> template<typename F>
int VisitInterfaceInner(TypeID id, Decorations d, F f) const; int VisitInterfaceInner(TypeID id, Decorations d, F f) const;
...@@ -430,6 +459,8 @@ namespace sw ...@@ -430,6 +459,8 @@ namespace sw
std::unordered_map<SpirvShader::ObjectID, Intermediate> intermediates; std::unordered_map<SpirvShader::ObjectID, Intermediate> intermediates;
std::unordered_map<SpirvShader::ObjectID, Pointer<Byte> > physicalPointers;
Value inputs = Value{MAX_INTERFACE_COMPONENTS}; Value inputs = Value{MAX_INTERFACE_COMPONENTS};
Value outputs = Value{MAX_INTERFACE_COMPONENTS}; Value outputs = Value{MAX_INTERFACE_COMPONENTS};
...@@ -461,6 +492,13 @@ namespace sw ...@@ -461,6 +492,13 @@ namespace sw
ASSERT(it != intermediates.end()); ASSERT(it != intermediates.end());
return it->second; return it->second;
} }
Pointer<Byte>& getPhysicalPointer(SpirvShader::ObjectID id)
{
auto it = physicalPointers.find(id);
assert(it != physicalPointers.end());
return it->second;
}
}; };
class GenericValue class GenericValue
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment