OpSelect implementation for pointers
Buffer Device Address adds the ability to perform an OpSelect
operation on pointers. This should only affect physical storage
pointers.
Tested locally using:
dEQP-VK.spirv_assembly.instruction.compute.physical_pointers.compute.reads_opselect_*
(These tests require the Buffer Device Address feature).
Bug: b/184952772
Change-Id: I75b999470e150ecb6bf9979ed900c21ffb2713b8
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/66288
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Commit-Queue: Alexis Hétu <sugoi@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 1a7dff9..c6377ed 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -2384,19 +2384,37 @@
SpirvShader::EmitResult SpirvShader::EmitSelect(InsnIterator insn, EmitState *state) const
{
auto &type = getType(insn.resultTypeId());
- auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
+ auto result = getObject(insn.resultId());
auto cond = Operand(this, state, insn.word(3));
auto condIsScalar = (cond.componentCount == 1);
- auto lhs = Operand(this, state, insn.word(4));
- auto rhs = Operand(this, state, insn.word(5));
- for(auto i = 0u; i < type.componentCount; i++)
+ switch(result.kind)
{
- auto sel = cond.Int(condIsScalar ? 0 : i);
- dst.move(i, (sel & lhs.Int(i)) | (~sel & rhs.Int(i))); // TODO: IfThenElse()
+ case Object::Kind::Pointer:
+ {
+ ASSERT(condIsScalar);
+ ASSERT(type.storageClass == spv::StorageClassPhysicalStorageBuffer);
+
+ auto &lhs = state->getPointer(insn.word(4));
+ auto &rhs = state->getPointer(insn.word(5));
+ state->createPointer(insn.resultId(), SIMD::Pointer::IfThenElse(cond.Int(0), lhs, rhs));
+ }
+ break;
+ default:
+ {
+ auto lhs = Operand(this, state, insn.word(4));
+ auto rhs = Operand(this, state, insn.word(5));
+ auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
+ for(auto i = 0u; i < type.componentCount; i++)
+ {
+ auto sel = cond.Int(condIsScalar ? 0 : i);
+ dst.move(i, (sel & lhs.Int(i)) | (~sel & rhs.Int(i))); // TODO: IfThenElse()
+ }
+ }
+ break;
}
- SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
+ SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), result);
SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
diff --git a/src/Reactor/Reactor.cpp b/src/Reactor/Reactor.cpp
index 83b8c38..f6f12ca 100644
--- a/src/Reactor/Reactor.cpp
+++ b/src/Reactor/Reactor.cpp
@@ -4621,6 +4621,23 @@
}
}
+Pointer4 Pointer4::IfThenElse(Int4 condition, const Pointer4 &lhs, const Pointer4 &rhs)
+{
+ std::array<Pointer<Byte>, 4> pointers;
+ for(int i = 0; i < 4; i++)
+ {
+ If(Extract(condition, i) != 0)
+ {
+ pointers[i] = lhs.getPointerForLane(i);
+ }
+ Else
+ {
+ pointers[i] = rhs.getPointerForLane(i);
+ }
+ }
+ return { pointers };
+}
+
#ifdef ENABLE_RR_PRINT
std::vector<rr::Value *> Pointer4::getPrintValues() const
{
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 175e2d8..1c1ca43 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -2203,6 +2203,7 @@
Pointer<Byte> getUniformPointer() const;
Pointer<Byte> getPointerForLane(int lane) const;
+ static Pointer4 IfThenElse(Int4 condition, const Pointer4 &lhs, const Pointer4 &rhs);
#ifdef ENABLE_RR_PRINT
std::vector<rr::Value *> getPrintValues() const;
@@ -3076,7 +3077,7 @@
// Calls the static function pointer fptr with the given arguments args.
template<typename Return, typename... CArgs, typename... RArgs>
-inline CToReactorT<Return> Call(Return(fptr)(CArgs...), RArgs &&...args)
+inline CToReactorT<Return> Call(Return(fptr)(CArgs...), RArgs &&... args)
{
return CallHelper<Return(CArgs...)>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
}
@@ -3084,7 +3085,7 @@
// Calls the static function pointer fptr with the given arguments args.
// Overload for calling functions with void return type.
template<typename... CArgs, typename... RArgs>
-inline void Call(void(fptr)(CArgs...), RArgs &&...args)
+inline void Call(void(fptr)(CArgs...), RArgs &&... args)
{
CallHelper<void(CArgs...)>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
}
@@ -3092,7 +3093,7 @@
// Calls the member function pointer fptr with the given arguments args.
// object can be a Class*, or a Pointer<Byte>.
template<typename Return, typename Class, typename C, typename... CArgs, typename... RArgs>
-inline CToReactorT<Return> Call(Return (Class::*fptr)(CArgs...), C &&object, RArgs &&...args)
+inline CToReactorT<Return> Call(Return (Class::*fptr)(CArgs...), C &&object, RArgs &&... args)
{
using Helper = CallHelper<Return(Class *, void *, CArgs...)>;
using fptrTy = decltype(fptr);
@@ -3116,7 +3117,7 @@
// Overload for calling functions with void return type.
// object can be a Class*, or a Pointer<Byte>.
template<typename Class, typename C, typename... CArgs, typename... RArgs>
-inline void Call(void (Class::*fptr)(CArgs...), C &&object, RArgs &&...args)
+inline void Call(void (Class::*fptr)(CArgs...), C &&object, RArgs &&... args)
{
using Helper = CallHelper<void(Class *, void *, CArgs...)>;
using fptrTy = decltype(fptr);
@@ -3173,7 +3174,7 @@
// Calls the Reactor function pointer fptr with the signature FUNCTION_SIGNATURE and arguments.
// Overload for calling functions with non-void return type.
template<typename FUNCTION_SIGNATURE, typename... RArgs>
-inline CToReactorT<NonVoidFunctionReturnType<FUNCTION_SIGNATURE>> Call(Pointer<Byte> fptr, RArgs &&...args)
+inline CToReactorT<NonVoidFunctionReturnType<FUNCTION_SIGNATURE>> Call(Pointer<Byte> fptr, RArgs &&... args)
{
return CallHelper<FUNCTION_SIGNATURE>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
}
@@ -3181,7 +3182,7 @@
// Calls the Reactor function pointer fptr with the signature FUNCTION_SIGNATURE and arguments.
// Overload for calling functions with void return type.
template<typename FUNCTION_SIGNATURE, typename... RArgs>
-inline VoidFunctionReturnType<FUNCTION_SIGNATURE> Call(Pointer<Byte> fptr, RArgs &&...args)
+inline VoidFunctionReturnType<FUNCTION_SIGNATURE> Call(Pointer<Byte> fptr, RArgs &&... args)
{
CallHelper<FUNCTION_SIGNATURE>::Call(fptr, CastToReactor(std::forward<RArgs>(args))...);
}