SubzeroReactor: implement missing atomic ops * Most use Subzero intrinsics, except for Min/MaxAtomic, which are emulated. * Added unit tests for each implemented function, but am not really testing that they behave as atomic functions. Only that they perform the expected operation. Bug: b/145754674 Change-Id: Ie3ec6e473ee8b448b28bf440da094ac03ac0005b Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/39829 Reviewed-by: Ben Clayton <bclayton@google.com> Tested-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp index 91de455..3c2888f 100644 --- a/src/Reactor/SubzeroReactor.cpp +++ b/src/Reactor/SubzeroReactor.cpp
@@ -89,7 +89,7 @@ # define __x86_64__ 1 #endif -static Ice::OptLevel toIce(rr::Optimization::Level level) +Ice::OptLevel toIce(rr::Optimization::Level level) { switch(level) { @@ -103,6 +103,20 @@ return Ice::Opt_2; } +Ice::Intrinsics::MemoryOrder stdToIceMemoryOrder(std::memory_order memoryOrder) +{ + switch(memoryOrder) + { + case std::memory_order_relaxed: return Ice::Intrinsics::MemoryOrderRelaxed; + case std::memory_order_consume: return Ice::Intrinsics::MemoryOrderConsume; + case std::memory_order_acquire: return Ice::Intrinsics::MemoryOrderAcquire; + case std::memory_order_release: return Ice::Intrinsics::MemoryOrderRelease; + case std::memory_order_acq_rel: return Ice::Intrinsics::MemoryOrderAcquireRelease; + case std::memory_order_seq_cst: return Ice::Intrinsics::MemoryOrderSequentiallyConsistent; + } + return Ice::Intrinsics::MemoryOrderInvalid; +} + class CPUID { public: @@ -1132,70 +1146,71 @@ return createAdd(ptr, index); } +static Value *createAtomicRMW(Ice::Intrinsics::AtomicRMWOperation rmwOp, Value *ptr, Value *value, std::memory_order memoryOrder) +{ + Ice::Variable *result = ::function->makeVariable(value->getType()); + + const Ice::Intrinsics::IntrinsicInfo intrinsic = { Ice::Intrinsics::AtomicRMW, Ice::Intrinsics::SideEffects_T, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_T }; + auto target = ::context->getConstantUndef(Ice::IceType_i32); + auto inst = Ice::InstIntrinsicCall::create(::function, 0, result, target, intrinsic); + auto op = ::context->getConstantInt32(rmwOp); + auto order = ::context->getConstantInt32(stdToIceMemoryOrder(memoryOrder)); + inst->addArg(op); + inst->addArg(ptr); + inst->addArg(value); + inst->addArg(order); + ::basicBlock->appendInst(inst); + + return V(result); +} + Value *Nucleus::createAtomicAdd(Value *ptr, Value *value, std::memory_order memoryOrder) { - UNIMPLEMENTED("createAtomicAdd"); - return nullptr; + return createAtomicRMW(Ice::Intrinsics::AtomicAdd, ptr, value, memoryOrder); } Value *Nucleus::createAtomicSub(Value *ptr, Value *value, std::memory_order memoryOrder) { - UNIMPLEMENTED("createAtomicSub"); - return nullptr; + return createAtomicRMW(Ice::Intrinsics::AtomicSub, ptr, value, memoryOrder); } Value *Nucleus::createAtomicAnd(Value *ptr, Value *value, std::memory_order memoryOrder) { - UNIMPLEMENTED("createAtomicAnd"); - return nullptr; + return createAtomicRMW(Ice::Intrinsics::AtomicAnd, ptr, value, memoryOrder); } Value *Nucleus::createAtomicOr(Value *ptr, Value *value, std::memory_order memoryOrder) { - UNIMPLEMENTED("createAtomicOr"); - return nullptr; + return createAtomicRMW(Ice::Intrinsics::AtomicOr, ptr, value, memoryOrder); } Value *Nucleus::createAtomicXor(Value *ptr, Value *value, std::memory_order memoryOrder) { - UNIMPLEMENTED("createAtomicXor"); - return nullptr; -} - -Value *Nucleus::createAtomicMin(Value *ptr, Value *value, std::memory_order memoryOrder) -{ - UNIMPLEMENTED("createAtomicMin"); - return nullptr; -} - -Value *Nucleus::createAtomicMax(Value *ptr, Value *value, std::memory_order memoryOrder) -{ - UNIMPLEMENTED("createAtomicMax"); - return nullptr; -} - -Value *Nucleus::createAtomicUMin(Value *ptr, Value *value, std::memory_order memoryOrder) -{ - UNIMPLEMENTED("createAtomicUMin"); - return nullptr; -} - -Value *Nucleus::createAtomicUMax(Value *ptr, Value *value, std::memory_order memoryOrder) -{ - UNIMPLEMENTED("createAtomicUMax"); - return nullptr; + return createAtomicRMW(Ice::Intrinsics::AtomicXor, ptr, value, memoryOrder); } Value *Nucleus::createAtomicExchange(Value *ptr, Value *value, std::memory_order memoryOrder) { - UNIMPLEMENTED("createAtomicExchange"); - return nullptr; + return createAtomicRMW(Ice::Intrinsics::AtomicExchange, ptr, value, memoryOrder); } Value *Nucleus::createAtomicCompareExchange(Value *ptr, Value *value, Value *compare, std::memory_order memoryOrderEqual, std::memory_order memoryOrderUnequal) { - UNIMPLEMENTED("createAtomicCompareExchange"); - return nullptr; + Ice::Variable *result = ::function->makeVariable(value->getType()); + + const Ice::Intrinsics::IntrinsicInfo intrinsic = { Ice::Intrinsics::AtomicCmpxchg, Ice::Intrinsics::SideEffects_T, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_T }; + auto target = ::context->getConstantUndef(Ice::IceType_i32); + auto inst = Ice::InstIntrinsicCall::create(::function, 0, result, target, intrinsic); + auto orderEq = ::context->getConstantInt32(stdToIceMemoryOrder(memoryOrderEqual)); + auto orderNeq = ::context->getConstantInt32(stdToIceMemoryOrder(memoryOrderUnequal)); + inst->addArg(ptr); + inst->addArg(compare); + inst->addArg(value); + inst->addArg(orderEq); + inst->addArg(orderNeq); + ::basicBlock->appendInst(inst); + + return V(result); } static Value *createCast(Ice::InstCast::OpKind op, Value *v, Type *destType) @@ -3603,8 +3618,14 @@ void Nucleus::createFence(std::memory_order memoryOrder) { - UNIMPLEMENTED("Subzero createFence()"); + const Ice::Intrinsics::IntrinsicInfo intrinsic = { Ice::Intrinsics::AtomicFence, Ice::Intrinsics::SideEffects_T, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F }; + auto target = ::context->getConstantUndef(Ice::IceType_i32); + auto inst = Ice::InstIntrinsicCall::create(::function, 0, nullptr, target, intrinsic); + auto order = ::context->getConstantInt32(stdToIceMemoryOrder(memoryOrder)); + inst->addArg(order); + ::basicBlock->appendInst(inst); } + Value *Nucleus::createMaskedLoad(Value *ptr, Type *elTy, Value *mask, unsigned int alignment, bool zeroMaskedLanes) { UNIMPLEMENTED("Subzero createMaskedLoad()"); @@ -3813,6 +3834,26 @@ } } +RValue<Int> MinAtomic(RValue<Pointer<Int>> x, RValue<Int> y, std::memory_order memoryOrder) +{ + return emulated::MinAtomic(x, y, memoryOrder); +} + +RValue<UInt> MinAtomic(RValue<Pointer<UInt>> x, RValue<UInt> y, std::memory_order memoryOrder) +{ + return emulated::MinAtomic(x, y, memoryOrder); +} + +RValue<Int> MaxAtomic(RValue<Pointer<Int>> x, RValue<Int> y, std::memory_order memoryOrder) +{ + return emulated::MaxAtomic(x, y, memoryOrder); +} + +RValue<UInt> MaxAtomic(RValue<Pointer<UInt>> x, RValue<UInt> y, std::memory_order memoryOrder) +{ + return emulated::MaxAtomic(x, y, memoryOrder); +} + void EmitDebugLocation() {} void EmitDebugVariable(Value *value) {} void FlushDebug() {}