Commit 3d497385 by Ben Clayton

src/Pipeline: Add SIMD::Pointer

Contains a base address, per-lane offsets and a boolean to say whether it is uniform across lanes. Use this instead of the std::pair for GetPointerToData and WalkExplicitLayoutAccessChain. Provides readability improvements. Bug: b/126126820 Change-Id: If3a010d7dc37c4f07ca489ae58195cdfed7ea559 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28568Tested-by: 's avatarChris Forbes <chrisforbes@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent b5bfa503
...@@ -829,17 +829,17 @@ namespace sw ...@@ -829,17 +829,17 @@ namespace sw
VisitInterfaceInner<F>(def.word(1), d, f); VisitInterfaceInner<F>(def.word(1), d, f);
} }
std::pair<Pointer<Byte>, SIMD::Int> SpirvShader::GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const SIMD::Pointer SpirvShader::GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const
{ {
auto &object = getObject(id); auto &object = getObject(id);
switch (object.kind) switch (object.kind)
{ {
case Object::Kind::NonDivergentPointer: case Object::Kind::NonDivergentPointer:
case Object::Kind::InterfaceVariable: case Object::Kind::InterfaceVariable:
return std::make_pair(routine->getPointer(id), SIMD::Int(0)); return SIMD::Pointer(routine->getPointer(id));
case Object::Kind::DivergentPointer: case Object::Kind::DivergentPointer:
return std::make_pair(routine->getPointer(id), routine->getIntermediate(id).Int(0)); return SIMD::Pointer(routine->getPointer(id), routine->getIntermediate(id).Int(0));
case Object::Kind::DescriptorSet: case Object::Kind::DescriptorSet:
{ {
...@@ -865,16 +865,16 @@ namespace sw ...@@ -865,16 +865,16 @@ namespace sw
arrayIndex; arrayIndex;
offset += routine->descriptorDynamicOffsets[dynamicBindingIndex]; offset += routine->descriptorDynamicOffsets[dynamicBindingIndex];
} }
return std::make_pair(data + offset, SIMD::Int(0)); return SIMD::Pointer(data + offset);
} }
default: default:
UNREACHABLE("Invalid pointer kind %d", int(object.kind)); UNREACHABLE("Invalid pointer kind %d", int(object.kind));
return std::make_pair(Pointer<Byte>(), SIMD::Int(0)); return SIMD::Pointer(Pointer<Byte>());
} }
} }
std::pair<Pointer<Byte>, SIMD::Int> SpirvShader::WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const SIMD::Pointer SpirvShader::WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
{ {
// Produce a offset into external memory in sizeof(float) units // Produce a offset into external memory in sizeof(float) units
...@@ -898,9 +898,7 @@ namespace sw ...@@ -898,9 +898,7 @@ namespace sw
} }
} }
SIMD::Int dynamicOffset; auto ptr = GetPointerToData(id, arrayIndex, routine);
Pointer<Byte> pointerBase;
std::tie(pointerBase, dynamicOffset) = GetPointerToData(id, arrayIndex, routine);
int constantOffset = 0; int constantOffset = 0;
...@@ -928,7 +926,7 @@ namespace sw ...@@ -928,7 +926,7 @@ namespace sw
if (obj.kind == Object::Kind::Constant) if (obj.kind == Object::Kind::Constant)
constantOffset += d.ArrayStride/sizeof(float) * GetConstantInt(indexIds[i]); constantOffset += d.ArrayStride/sizeof(float) * GetConstantInt(indexIds[i]);
else else
dynamicOffset += SIMD::Int(d.ArrayStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0); ptr.offset += SIMD::Int(d.ArrayStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0);
typeId = type.element; typeId = type.element;
break; break;
} }
...@@ -941,7 +939,7 @@ namespace sw ...@@ -941,7 +939,7 @@ namespace sw
if (obj.kind == Object::Kind::Constant) if (obj.kind == Object::Kind::Constant)
constantOffset += d.MatrixStride/sizeof(float) * GetConstantInt(indexIds[i]); constantOffset += d.MatrixStride/sizeof(float) * GetConstantInt(indexIds[i]);
else else
dynamicOffset += SIMD::Int(d.MatrixStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0); ptr.offset += SIMD::Int(d.MatrixStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0);
typeId = type.element; typeId = type.element;
break; break;
} }
...@@ -951,7 +949,7 @@ namespace sw ...@@ -951,7 +949,7 @@ namespace sw
if (obj.kind == Object::Kind::Constant) if (obj.kind == Object::Kind::Constant)
constantOffset += GetConstantInt(indexIds[i]); constantOffset += GetConstantInt(indexIds[i]);
else else
dynamicOffset += routine->getIntermediate(indexIds[i]).Int(0); ptr.offset += routine->getIntermediate(indexIds[i]).Int(0);
typeId = type.element; typeId = type.element;
break; break;
} }
...@@ -960,7 +958,9 @@ namespace sw ...@@ -960,7 +958,9 @@ namespace sw
} }
} }
return std::make_pair(pointerBase, dynamicOffset + SIMD::Int(constantOffset)); ptr.offset += SIMD::Int(constantOffset);
return ptr;
} }
SIMD::Int SpirvShader::WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const SIMD::Int SpirvShader::WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
...@@ -1854,16 +1854,14 @@ namespace sw ...@@ -1854,16 +1854,14 @@ namespace sw
UNIMPLEMENTED("StorageClassImage load not yet implemented"); UNIMPLEMENTED("StorageClassImage load not yet implemented");
} }
SIMD::Int offsets; auto ptr = GetPointerToData(pointerId, 0, routine);
Pointer<Float> ptrBase;
std::tie(ptrBase, offsets) = GetPointerToData(pointerId, 0, routine);
bool interleavedByLane = IsStorageInterleavedByLane(pointerTy.storageClass); bool interleavedByLane = IsStorageInterleavedByLane(pointerTy.storageClass);
auto anyInactiveLanes = AnyFalse(state->activeLaneMask()); auto anyInactiveLanes = AnyFalse(state->activeLaneMask());
auto load = std::unique_ptr<SIMD::Float[]>(new SIMD::Float[resultTy.sizeInComponents]); auto load = std::unique_ptr<SIMD::Float[]>(new SIMD::Float[resultTy.sizeInComponents]);
If(pointer.kind == Object::Kind::DivergentPointer || anyInactiveLanes) If(!ptr.uniform || anyInactiveLanes)
{ {
// Divergent offsets or masked lanes. // Divergent offsets or masked lanes.
for (auto i = 0u; i < resultTy.sizeInComponents; i++) for (auto i = 0u; i < resultTy.sizeInComponents; i++)
...@@ -1873,9 +1871,9 @@ namespace sw ...@@ -1873,9 +1871,9 @@ namespace sw
{ {
If(Extract(state->activeLaneMask(), j) != 0) If(Extract(state->activeLaneMask(), j) != 0)
{ {
Int offset = Int(i) + Extract(offsets, j); Int offset = Int(i) + Extract(ptr.offset, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; } if (interleavedByLane) { offset = offset * SIMD::Width + j; }
load[i] = Insert(load[i], Load(&ptrBase[offset], sizeof(float), atomic, memoryOrder), j); load[i] = Insert(load[i], Load(&ptr.base[offset], sizeof(float), atomic, memoryOrder), j);
} }
} }
} }
...@@ -1886,7 +1884,7 @@ namespace sw ...@@ -1886,7 +1884,7 @@ namespace sw
if (interleavedByLane) if (interleavedByLane)
{ {
// Lane-interleaved data. // Lane-interleaved data.
Pointer<SIMD::Float> src = ptrBase; Pointer<SIMD::Float> src = ptr.base;
for (auto i = 0u; i < resultTy.sizeInComponents; i++) for (auto i = 0u; i < resultTy.sizeInComponents; i++)
{ {
load[i] = Load(&src[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment load[i] = Load(&src[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
...@@ -1897,7 +1895,7 @@ namespace sw ...@@ -1897,7 +1895,7 @@ namespace sw
// Non-interleaved data. // Non-interleaved data.
for (auto i = 0u; i < resultTy.sizeInComponents; i++) for (auto i = 0u; i < resultTy.sizeInComponents; i++)
{ {
load[i] = RValue<SIMD::Float>(Load(&ptrBase[i], sizeof(float), atomic, memoryOrder)); // TODO: optimize alignment load[i] = RValue<SIMD::Float>(Load(&ptr.base[i], sizeof(float), atomic, memoryOrder)); // TODO: optimize alignment
} }
} }
} }
...@@ -1937,9 +1935,7 @@ namespace sw ...@@ -1937,9 +1935,7 @@ namespace sw
UNIMPLEMENTED("StorageClassImage store not yet implemented"); UNIMPLEMENTED("StorageClassImage store not yet implemented");
} }
SIMD::Int offsets; auto ptr = GetPointerToData(pointerId, 0, routine);
Pointer<Float> ptrBase;
std::tie(ptrBase, offsets) = GetPointerToData(pointerId, 0, routine);
bool interleavedByLane = IsStorageInterleavedByLane(pointerTy.storageClass); bool interleavedByLane = IsStorageInterleavedByLane(pointerTy.storageClass);
auto anyInactiveLanes = AnyFalse(state->activeLaneMask()); auto anyInactiveLanes = AnyFalse(state->activeLaneMask());
...@@ -1948,7 +1944,7 @@ namespace sw ...@@ -1948,7 +1944,7 @@ namespace sw
{ {
// Constant source data. // Constant source data.
auto src = reinterpret_cast<float *>(object.constantValue.get()); auto src = reinterpret_cast<float *>(object.constantValue.get());
If(pointer.kind == Object::Kind::DivergentPointer || anyInactiveLanes) If(!ptr.uniform || anyInactiveLanes)
{ {
// Divergent offsets or masked lanes. // Divergent offsets or masked lanes.
...@@ -1958,9 +1954,9 @@ namespace sw ...@@ -1958,9 +1954,9 @@ namespace sw
{ {
If(Extract(state->activeLaneMask(), j) != 0) If(Extract(state->activeLaneMask(), j) != 0)
{ {
Int offset = Int(i) + Extract(offsets, j); Int offset = Int(i) + Extract(ptr.offset, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; } if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Store(RValue<Float>(src[i]), &ptrBase[offset], sizeof(float), atomic, memoryOrder); Store(RValue<Float>(src[i]), &ptr.base[offset], sizeof(float), atomic, memoryOrder);
} }
} }
} }
...@@ -1969,7 +1965,7 @@ namespace sw ...@@ -1969,7 +1965,7 @@ namespace sw
{ {
// Constant source data. // Constant source data.
// No divergent offsets or masked lanes. // No divergent offsets or masked lanes.
Pointer<SIMD::Float> dst = ptrBase; Pointer<SIMD::Float> dst = ptr.base;
for (auto i = 0u; i < elementTy.sizeInComponents; i++) for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{ {
Store(RValue<SIMD::Float>(src[i]), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment Store(RValue<SIMD::Float>(src[i]), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
...@@ -1980,7 +1976,7 @@ namespace sw ...@@ -1980,7 +1976,7 @@ namespace sw
{ {
// Intermediate source data. // Intermediate source data.
auto &src = routine->getIntermediate(objectId); auto &src = routine->getIntermediate(objectId);
If(pointer.kind == Object::Kind::DivergentPointer || anyInactiveLanes) If(!ptr.uniform || anyInactiveLanes)
{ {
// Divergent offsets or masked lanes. // Divergent offsets or masked lanes.
for (auto i = 0u; i < elementTy.sizeInComponents; i++) for (auto i = 0u; i < elementTy.sizeInComponents; i++)
...@@ -1989,9 +1985,9 @@ namespace sw ...@@ -1989,9 +1985,9 @@ namespace sw
{ {
If(Extract(state->activeLaneMask(), j) != 0) If(Extract(state->activeLaneMask(), j) != 0)
{ {
Int offset = Int(i) + Extract(offsets, j); Int offset = Int(i) + Extract(ptr.offset, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; } if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Store(Extract(src.Float(i), j), &ptrBase[offset], sizeof(float), atomic, memoryOrder); Store(Extract(src.Float(i), j), &ptr.base[offset], sizeof(float), atomic, memoryOrder);
} }
} }
} }
...@@ -2002,7 +1998,7 @@ namespace sw ...@@ -2002,7 +1998,7 @@ namespace sw
if (interleavedByLane) if (interleavedByLane)
{ {
// Lane-interleaved data. // Lane-interleaved data.
Pointer<SIMD::Float> dst = ptrBase; Pointer<SIMD::Float> dst = ptr.base;
for (auto i = 0u; i < elementTy.sizeInComponents; i++) for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{ {
Store(src.Float(i), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment Store(src.Float(i), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
...@@ -2011,7 +2007,7 @@ namespace sw ...@@ -2011,7 +2007,7 @@ namespace sw
else else
{ {
// Intermediate source data. Non-interleaved data. // Intermediate source data. Non-interleaved data.
Pointer<SIMD::Float> dst = ptrBase; Pointer<SIMD::Float> dst = ptr.base;
for (auto i = 0u; i < elementTy.sizeInComponents; i++) for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{ {
Store<SIMD::Float>(SIMD::Float(src.Float(i)), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment Store<SIMD::Float>(SIMD::Float(src.Float(i)), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
...@@ -2039,9 +2035,9 @@ namespace sw ...@@ -2039,9 +2035,9 @@ namespace sw
type.storageClass == spv::StorageClassUniform || type.storageClass == spv::StorageClassUniform ||
type.storageClass == spv::StorageClassStorageBuffer) type.storageClass == spv::StorageClassStorageBuffer)
{ {
auto baseAndOffset = WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine); auto ptr = WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine);
routine->createPointer(resultId, baseAndOffset.first); routine->createPointer(resultId, ptr.base);
routine->createIntermediate(resultId, type.sizeInComponents).move(0, baseAndOffset.second); routine->createIntermediate(resultId, type.sizeInComponents).move(0, ptr.offset);
} }
else else
{ {
......
...@@ -59,6 +59,22 @@ namespace sw ...@@ -59,6 +59,22 @@ namespace sw
using Float = rr::Float4; using Float = rr::Float4;
using Int = rr::Int4; using Int = rr::Int4;
using UInt = rr::UInt4; using UInt = rr::UInt4;
struct Pointer
{
Pointer(rr::Pointer<Byte> base) : base(base), offset(0), uniform(true) {}
Pointer(rr::Pointer<Byte> base, SIMD::Int offset) : base(base), offset(offset), uniform(false) {}
// Base address for the pointer, common across all lanes.
rr::Pointer<rr::Float> base;
// Per lane offsets from base.
// If uniform is false, all offsets are considered zero.
Int offset;
// True if all offsets are zero.
bool uniform;
};
} }
// Incrementally constructed complex bundle of rvalues // Incrementally constructed complex bundle of rvalues
...@@ -562,16 +578,17 @@ namespace sw ...@@ -562,16 +578,17 @@ namespace sw
void ProcessInterfaceVariable(Object &object); void ProcessInterfaceVariable(Object &object);
// Returns a base pointer and per-lane offset to the underlying data for // Returns a SIMD::Pointer to the underlying data for the given pointer
// the given pointer object. Handles objects of the following kinds: // object.
// Handles objects of the following kinds:
// • DescriptorSet // • DescriptorSet
// • DivergentPointer // • DivergentPointer
// • InterfaceVariable // • InterfaceVariable
// • NonDivergentPointer // • NonDivergentPointer
// Calling GetPointerToData with objects of any other kind will assert. // Calling GetPointerToData with objects of any other kind will assert.
std::pair<Pointer<Byte>, SIMD::Int> GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const; SIMD::Pointer GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const;
std::pair<Pointer<Byte>, SIMD::Int> WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const; SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
SIMD::Int WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const; SIMD::Int WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const; uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const;
......
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