Implement some common forms of OpAccessChain Bug: b/124388146 Change-Id: I948ad5607c1e41be920006aaa4b7d18d210af4a3 Reviewed-on: https://swiftshader-review.googlesource.com/c/24790 Tested-by: Chris Forbes <chrisforbes@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com> Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp index cdd3a63..aa48093 100644 --- a/src/Pipeline/SpirvShader.cpp +++ b/src/Pipeline/SpirvShader.cpp
@@ -487,6 +487,56 @@ VisitInterfaceInner<F>(def.word(1), d, f); } + Int4 SpirvShader::WalkAccessChain(uint32_t id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const + { + // TODO: think about decorations, to make this work on location based interfaces + // TODO: think about explicit layout (UBO/SSBO) storage classes + // TODO: avoid doing per-lane work in some cases if we can? + + Int4 res = Int4(0); + auto & baseObject = getObject(id); + auto typeId = baseObject.definition.word(1); + + if (baseObject.kind == Object::Kind::Value) + res += As<Int4>((*routine->lvalues[id])[0]); + + for (auto i = 0u; i < numIndexes; i++) + { + auto & type = getType(typeId); + switch (type.definition.opcode()) + { + case spv::OpTypeStruct: + { + int memberIndex = GetConstantInt(indexIds[i]); + int offsetIntoStruct = 0; + for (auto j = 0; j < memberIndex; j++) { + offsetIntoStruct += getType(type.definition.word(2 + memberIndex)).sizeInComponents; + } + res += Int4(offsetIntoStruct); + break; + } + + case spv::OpTypeVector: + case spv::OpTypeMatrix: + case spv::OpTypeArray: + { + auto stride = getType(type.definition.word(2)).sizeInComponents; + auto & obj = getObject(indexIds[i]); + if (obj.kind == Object::Kind::Constant) + res += Int4(stride * GetConstantInt(indexIds[i])); + else + res += Int4(stride) * As<Int4>((*(routine->lvalues)[indexIds[i]])[0]); + break; + } + + default: + UNIMPLEMENTED("Unexpected type in WalkAccessChain"); + } + } + + return res; + } + void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg) { switch (decoration) @@ -660,6 +710,32 @@ } break; } + case spv::OpAccessChain: + { + auto &object = getObject(insn.word(2)); + auto &type = getType(insn.word(1)); + auto &base = getObject(insn.word(3)); + routine->createLvalue(insn.word(2), type.sizeInComponents); // TODO: this should be an ssavalue! + auto &pointerBase = getObject(object.pointerBase); + assert(type.sizeInComponents == 1); + assert(base.pointerBase == object.pointerBase); + + if (pointerBase.kind == Object::Kind::InterfaceVariable) + { + UNIMPLEMENTED("Location-based OpAccessChain not yet implemented"); + } + + if (pointerBase.storageClass == spv::StorageClassImage || + pointerBase.storageClass == spv::StorageClassUniform || + pointerBase.storageClass == spv::StorageClassUniformConstant) + { + UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented"); + } + + auto & dst = *(routine->lvalues)[insn.word(2)]; + dst[0] = As<Float4>(WalkAccessChain(insn.word(3), insn.wordCount() - 4, insn.wordPointer(4), routine)); + break; + } case spv::OpStore: { auto &object = getObject(insn.word(2));
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp index ec8f308..86dfaed 100644 --- a/src/Pipeline/SpirvShader.hpp +++ b/src/Pipeline/SpirvShader.hpp
@@ -72,6 +72,12 @@ return iter[n]; } + uint32_t const * wordPointer(uint32_t n) const + { + ASSERT(n < wordCount()); + return &iter[n]; + } + bool operator!=(InsnIterator const &other) const { return iter != other.iter; @@ -275,6 +281,8 @@ uint32_t GetConstantInt(uint32_t id) const; void ProcessInterfaceVariable(Object &object); + + Int4 WalkAccessChain(uint32_t id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const; }; }