SpirvShader: Implement OpArrayLength
Tests: dEQP-VK.ssbo.unsized_array_length.*
Bug: b/132336662
Change-Id: I122788b1096795ff32b87418e2d65cbe1641af33
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31010
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 423706d..4ffa5e4 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -876,6 +876,7 @@
case spv::OpImageTexelPointer:
case spv::OpGroupNonUniformElect:
case spv::OpCopyObject:
+ case spv::OpArrayLength:
// Instructions that yield an intermediate value or divergent pointer
DefineResult(insn);
break;
@@ -2484,6 +2485,9 @@
case spv::OpGroupNonUniformElect:
return EmitGroupNonUniform(insn, state);
+ case spv::OpArrayLength:
+ return EmitArrayLength(insn, state);
+
default:
UNREACHABLE("%s", OpcodeName(opcode).c_str());
break;
@@ -5579,6 +5583,39 @@
return EmitResult::Continue;
}
+ SpirvShader::EmitResult SpirvShader::EmitArrayLength(InsnIterator insn, EmitState *state) const
+ {
+ auto resultTyId = Type::ID(insn.word(1));
+ auto resultId = Object::ID(insn.word(2));
+ auto structPtrId = Object::ID(insn.word(3));
+ auto arrayFieldIdx = insn.word(4);
+
+ auto &resultType = getType(resultTyId);
+ ASSERT(resultType.sizeInComponents == 1);
+ ASSERT(resultType.definition.opcode() == spv::OpTypeInt);
+
+ auto &structPtrTy = getType(getObject(structPtrId).type);
+ auto &structTy = getType(structPtrTy.element);
+ auto &arrayTy = getType(structTy.definition.word(2 + arrayFieldIdx));
+ ASSERT(arrayTy.definition.opcode() == spv::OpTypeRuntimeArray);
+ auto &arrayElTy = getType(arrayTy.element);
+
+ auto &result = state->routine->createIntermediate(resultId, 1);
+ auto structBase = GetPointerToData(structPtrId, 0, state->routine);
+
+ Decorations d = {};
+ ApplyDecorationsForIdMember(&d, structPtrTy.element, arrayFieldIdx);
+ ASSERT(d.HasOffset);
+
+ auto arrayBase = structBase + d.Offset;
+ auto arraySizeInBytes = SIMD::Int(arrayBase.limit) - arrayBase.offsets();
+ auto arrayLength = arraySizeInBytes / SIMD::Int(arrayElTy.sizeInComponents * sizeof(float));
+
+ result.move(0, SIMD::Int(arrayLength));
+
+ return EmitResult::Continue;
+ }
+
uint32_t SpirvShader::GetConstScalarInt(Object::ID id) const
{
auto &scopeObj = getObject(id);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 292f4d2..3f71fb5 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -944,6 +944,7 @@
EmitResult EmitControlBarrier(InsnIterator insn, EmitState *state) const;
EmitResult EmitMemoryBarrier(InsnIterator insn, EmitState *state) const;
EmitResult EmitGroupNonUniform(InsnIterator insn, EmitState *state) const;
+ EmitResult EmitArrayLength(InsnIterator insn, EmitState *state) const;
void GetImageDimensions(SpirvRoutine const *routine, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const;
SIMD::Pointer GetTexelAddress(SpirvRoutine const *routine, SIMD::Pointer base, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const;