Add support for OpAtomicCompareExchange
Includes associated Reactor plumbing.
Bug: b/130768731
Bug: b/127472316
Test: dEQP-VK.image.*
Change-Id: I700eb29f976410b59778e4ed162066b84a55a974
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29456
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 2525911..32d8bd7 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -687,6 +687,7 @@
case spv::OpAtomicOr:
case spv::OpAtomicXor:
case spv::OpAtomicExchange:
+ case spv::OpAtomicCompareExchange:
case spv::OpPhi:
case spv::OpImageSampleImplicitLod:
case spv::OpImageQuerySize:
@@ -1998,6 +1999,9 @@
case spv::OpAtomicExchange:
return EmitAtomicOp(insn, state);
+ case spv::OpAtomicCompareExchange:
+ return EmitAtomicCompareExchange(insn, state);
+
case spv::OpAccessChain:
case spv::OpInBoundsAccessChain:
return EmitAccessChain(insn, state);
@@ -4784,6 +4788,40 @@
return EmitResult::Continue;
}
+ SpirvShader::EmitResult SpirvShader::EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const
+ {
+ // Separate from EmitAtomicOp due to different instruction encoding
+ auto &resultType = getType(Type::ID(insn.word(1)));
+ Object::ID resultId = insn.word(2);
+
+ auto memorySemanticsEqual = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(5)).constantValue[0]);
+ auto memoryOrderEqual = MemoryOrder(memorySemanticsEqual);
+ auto memorySemanticsUnequal = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(6)).constantValue[0]);
+ auto memoryOrderUnequal = MemoryOrder(memorySemanticsUnequal);
+
+ auto value = GenericValue(this, state->routine, insn.word(7));
+ auto comparator = GenericValue(this, state->routine, insn.word(8));
+ auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
+ auto ptr = Pointer<UInt>(state->routine->getPointer(insn.word(3)));
+ auto offsets = state->routine->getIntermediate(insn.word(3)).UInt(0);
+
+ SIMD::UInt x;
+ for (int j = 0; j < SIMD::Width; j++)
+ {
+ If(Extract(state->activeLaneMask(), j) != 0)
+ {
+ auto offset = Extract(offsets, j);
+ auto laneValue = Extract(value.UInt(0), j);
+ auto laneComparator = Extract(comparator.UInt(0), j);
+ UInt v = CompareExchangeAtomic(&ptr[offset], laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
+ x = Insert(x, v, j);
+ }
+ }
+
+ dst.move(0, x);
+ return EmitResult::Continue;
+ }
+
void SpirvShader::emitEpilog(SpirvRoutine *routine) const
{
for (auto insn : *this)