VisitInterfaceInner<F>(def.word(1), d, f);
}
- Int4 SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
+ SIMD::Int SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
{
// TODO: think about explicit layout (UBO/SSBO) storage classes
// TODO: avoid doing per-lane work in some cases if we can?
int constantOffset = 0;
- Int4 dynamicOffset = Int4(0);
+ SIMD::Int dynamicOffset = SIMD::Int(0);
auto &baseObject = getObject(id);
TypeID typeId = getType(baseObject.type).element;
// The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
// Start with its offset and build from there.
if (baseObject.kind == Object::Kind::Value)
- dynamicOffset += As<Int4>(routine->getIntermediate(id)[0]);
+ dynamicOffset += As<SIMD::Int>(routine->getIntermediate(id)[0]);
for (auto i = 0u; i < numIndexes; i++)
{
if (obj.kind == Object::Kind::Constant)
constantOffset += stride * GetConstantInt(indexIds[i]);
else
- dynamicOffset += Int4(stride) * As<Int4>(routine->getIntermediate(indexIds[i])[0]);
+ dynamicOffset += SIMD::Int(stride) * As<SIMD::Int>(routine->getIntermediate(indexIds[i])[0]);
typeId = type.element;
break;
}
}
}
- return dynamicOffset + Int4(constantOffset);
+ return dynamicOffset + SIMD::Int(constantOffset);
}
uint32_t SpirvShader::WalkLiteralAccessChain(TypeID typeId, uint32_t numIndexes, uint32_t const *indexes) const
if (pointer.kind == Object::Kind::Value)
{
- auto offsets = As<Int4>(routine->getIntermediate(insn.word(3))[0]);
+ auto offsets = As<SIMD::Int>(routine->getIntermediate(insn.word(3))[0]);
for (auto i = 0u; i < objectTy.sizeInComponents; i++)
{
// i wish i had a Float,Float,Float,Float constructor here..
- Float4 v;
- for (int j = 0; j < 4; j++)
+ SIMD::Float v;
+ for (int j = 0; j < SIMD::Width; j++)
{
Int offset = Int(i) + Extract(offsets, j);
v = Insert(v, Extract(ptrBase[offset], j), j);
UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
}
auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
- dst.emplace(0, As<Float4>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
+ dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
break;
}
case spv::OpStore:
if (pointer.kind == Object::Kind::Value)
{
- auto offsets = As<Int4>(routine->getIntermediate(pointerId)[0]);
+ auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{
// Scattered store
- for (int j = 0; j < 4; j++)
+ for (int j = 0; j < SIMD::Width; j++)
{
auto dst = ptrBase[Int(i) + Extract(offsets, j)];
dst = Insert(dst, Float(src[i]), j);
// no divergent offsets
for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{
- ptrBase[i] = RValue<Float4>(src[i]);
+ ptrBase[i] = RValue<SIMD::Float>(src[i]);
}
}
}
if (pointer.kind == Object::Kind::Value)
{
- auto offsets = As<Int4>(routine->getIntermediate(pointerId)[0]);
+ auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
for (auto i = 0u; i < elementTy.sizeInComponents; i++)
{
// Scattered store
- for (int j = 0; j < 4; j++)
+ for (int j = 0; j < SIMD::Width; j++)
{
auto dst = ptrBase[Int(i) + Extract(offsets, j)];
dst = Insert(dst, Extract(src[i], j), j);
{
// Undefined value. Until we decide to do real undef values, zero is as good
// a value as any
- dst.emplace(i, RValue<Float4>(0.0f));
+ dst.emplace(i, RValue<SIMD::Float>(0.0f));
}
else if (selector < type.sizeInComponents)
{
namespace sw
{
+ // Forward declarations.
+ class SpirvRoutine;
+
+ // SIMD contains types that represent multiple scalars packed into a single
+ // vector data type. Types in the SIMD namespace provide a semantic hint
+ // that the data should be treated as a per-execution-lane scalar instead of
+ // a typical euclidean-style vector type.
+ namespace SIMD
+ {
+ // Width is the number of per-lane scalars packed into each SIMD vector.
+ static constexpr int Width = 4;
+
+ using Float = rr::Float4;
+ using Int = rr::Int4;
+ }
+
// Incrementally constructed complex bundle of rvalues
// Effectively a restricted vector, supporting only:
// - allocation to a (runtime-known) fixed size
class Intermediate
{
public:
- using Scalar = RValue<Float4>;
+ using Scalar = RValue<SIMD::Float>;
Intermediate(uint32_t size) : contents(new ContentsType[size]), size(size) {}
new (&contents[n]) Scalar(value);
}
+ void emplace(uint32_t n, const Scalar& value)
+ {
+ assert(n < size);
+ new (&contents[n]) Scalar(value);
+ }
+
Scalar const & operator[](uint32_t n) const
{
assert(n < size);
uint32_t size;
};
- class SpirvRoutine;
-
class SpirvShader
{
public:
void ProcessInterfaceVariable(Object &object);
- Int4 WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
+ SIMD::Int WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
uint32_t WalkLiteralAccessChain(TypeID id, uint32_t numIndexes, uint32_t const *indexes) const;
};
class SpirvRoutine
{
public:
- using Value = Array<Float4>;
+ using Value = Array<SIMD::Float>;
+
std::unordered_map<SpirvShader::ObjectID, Value> lvalues;
std::unordered_map<SpirvShader::ObjectID, Intermediate> intermediates;
obj(shader->getObject(objId)),
intermediate(obj.kind == SpirvShader::Object::Kind::Value ? &routine->getIntermediate(objId) : nullptr) {}
- RValue<Float4> operator[](uint32_t i) const
+ RValue<SIMD::Float> operator[](uint32_t i) const
{
if (intermediate)
return (*intermediate)[i];
auto constantValue = reinterpret_cast<float *>(obj.constantValue.get());
- return RValue<Float4>(constantValue[i]);
+ return RValue<SIMD::Float>(constantValue[i]);
}
};