SpirvShader: Implement OpGroupNonUniformElect The only elect function we'll need to implement for Pastel 1.0. Used by memory barrier tests, but not tested on its own. Bug: b/131667233 Change-Id: I5309fa6b49c49091226fbaaca4e46363f6dff534 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30208 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Presubmit-Ready: Ben Clayton <bclayton@google.com> Reviewed-by: Chris Forbes <chrisforbes@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com> Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp index 60ba39b..9f5246d 100644 --- a/src/Pipeline/SpirvShader.cpp +++ b/src/Pipeline/SpirvShader.cpp
@@ -862,6 +862,7 @@ case spv::OpImageQuerySize: case spv::OpImageRead: case spv::OpImageTexelPointer: + case spv::OpGroupNonUniformElect: // Instructions that yield an intermediate value or divergent pointer DefineResult(insn); break; @@ -2447,6 +2448,9 @@ case spv::OpCopyMemory: return EmitCopyMemory(insn, state); + case spv::OpGroupNonUniformElect: + return EmitGroupNonUniform(insn, state); + default: UNREACHABLE("%s", OpcodeName(opcode).c_str()); break; @@ -5321,6 +5325,43 @@ return EmitResult::Continue; } + SpirvShader::EmitResult SpirvShader::EmitGroupNonUniform(InsnIterator insn, EmitState *state) const + { + auto &type = getType(Type::ID(insn.word(1))); + Object::ID resultId = insn.word(2); + auto scope = GetScope(insn.word(3)); + ASSERT_MSG(scope == spv::ScopeSubgroup, "Scope for Non Uniform Group Operations must be Subgroup for Vulkan 1.1"); + + auto &dst = state->routine->createIntermediate(resultId, type.sizeInComponents); + + switch (insn.opcode()) + { + case spv::OpGroupNonUniformElect: + { + // Result is true only in the active invocation with the lowest id + // in the group, otherwise result is false. + SIMD::Int active = state->activeLaneMask(); + // TODO: Would be nice if we could write this as: + // elect = active & ~(active.Oxyz | active.OOxy | active.OOOx) + auto v0111 = SIMD::Int(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); + auto elect = active & ~(v0111 & (active.xxyz | active.xxxy | active.xxxx)); + dst.move(0, elect); + break; + } + default: + UNIMPLEMENTED("EmitGroupNonUniform op: %s", OpcodeName(type.opcode()).c_str()); + } + return EmitResult::Continue; + } + + spv::Scope SpirvShader::GetScope(Object::ID id) const + { + auto &scopeObj = getObject(id); + ASSERT(scopeObj.kind == Object::Kind::Constant); + ASSERT(getType(scopeObj.type).sizeInComponents == 1); + return spv::Scope(scopeObj.constantValue[0]); + } + void SpirvShader::emitEpilog(SpirvRoutine *routine) const { for (auto insn : *this)
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp index cf38289..77da4d5 100644 --- a/src/Pipeline/SpirvShader.hpp +++ b/src/Pipeline/SpirvShader.hpp
@@ -906,8 +906,10 @@ EmitResult EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const; EmitResult EmitSampledImageCombineOrSplit(InsnIterator insn, EmitState *state) const; EmitResult EmitCopyMemory(InsnIterator insn, EmitState *state) const; + EmitResult EmitGroupNonUniform(InsnIterator insn, EmitState *state) const; SIMD::Pointer GetTexelAddress(SpirvRoutine const * routine, SIMD::Pointer base, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize) const; + spv::Scope GetScope(Object::ID id) const; // OpcodeName() returns the name of the opcode op. // If NDEBUG is defined, then OpcodeName() will only return the numerical code.