LLVMReactor: Fix atomic loads and stores of non-scalar types.
The documentation and verifier both say the pointee needs to be a integer, pointer, or floating point type.
It looks like invalid atomic stores may be lowered to __atomic_load / __atomic_store via the AtomicExpandPass, but this comes much later in the transform pipeline, and before the verifier.
Bug: b/131914569
Bug: b/127472316
Change-Id: Ieae5527ca5d65c890251c802baeaca6c5a9eacbb
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30568
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 11ea23a..83e0b01 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -1273,11 +1273,36 @@
// Fallthrough to non-emulated case.
case Type_LLVM:
{
- ASSERT(V(ptr)->getType()->getContainedType(0) == T(type));
- auto load = new llvm::LoadInst(V(ptr), "", isVolatile, alignment);
- load->setAtomic(atomicOrdering(atomic, memoryOrder));
-
- return V(::builder->Insert(load));
+ auto elTy = T(type);
+ ASSERT(V(ptr)->getType()->getContainedType(0) == elTy);
+ if (atomic && !(elTy->isIntegerTy() || elTy->isPointerTy() || elTy->isFloatTy()))
+ {
+ // atomic load operand must have integer, pointer, or floating point type
+ // Fall back to using:
+ // void __atomic_load(size_t size, void *ptr, void *ret, int ordering)
+ auto sizetTy = ::llvm::IntegerType::get(*::context, sizeof(size_t) * 8);
+ auto intTy = ::llvm::IntegerType::get(*::context, sizeof(int) * 8);
+ auto i8Ty = ::llvm::Type::getInt8Ty(*::context);
+ auto i8PtrTy = i8Ty->getPointerTo();
+ auto voidTy = ::llvm::Type::getVoidTy(*::context);
+ auto funcTy = ::llvm::FunctionType::get(voidTy, {sizetTy, i8PtrTy, i8PtrTy, intTy}, false);
+ auto func = ::module->getOrInsertFunction("__atomic_load", funcTy);
+ auto size = ::module->getDataLayout().getTypeStoreSize(elTy);
+ auto out = allocateStackVariable(type);
+ ::builder->CreateCall(func, {
+ ::llvm::ConstantInt::get(sizetTy, size),
+ ::builder->CreatePointerCast(V(ptr), i8PtrTy),
+ ::builder->CreatePointerCast(V(out), i8PtrTy),
+ ::llvm::ConstantInt::get(intTy, uint64_t(atomicOrdering(true, memoryOrder))),
+ });
+ return V(::builder->CreateLoad(V(out)));
+ }
+ else
+ {
+ auto load = new llvm::LoadInst(V(ptr), "", isVolatile, alignment);
+ load->setAtomic(atomicOrdering(atomic, memoryOrder));
+ return V(::builder->Insert(load));
+ }
}
default:
UNREACHABLE("asInternalType(type): %d", int(asInternalType(type)));
@@ -1313,9 +1338,35 @@
// Fallthrough to non-emulated case.
case Type_LLVM:
{
- ASSERT(V(ptr)->getType()->getContainedType(0) == T(type));
- auto store = ::builder->Insert(new llvm::StoreInst(V(value), V(ptr), isVolatile, alignment));
- store->setAtomic(atomicOrdering(atomic, memoryOrder));
+ auto elTy = T(type);
+ ASSERT(V(ptr)->getType()->getContainedType(0) == elTy);
+ if (atomic && !(elTy->isIntegerTy() || elTy->isPointerTy() || elTy->isFloatTy()))
+ {
+ // atomic store operand must have integer, pointer, or floating point type
+ // Fall back to using:
+ // void __atomic_store(size_t size, void *ptr, void *val, int ordering)
+ auto sizetTy = ::llvm::IntegerType::get(*::context, sizeof(size_t) * 8);
+ auto intTy = ::llvm::IntegerType::get(*::context, sizeof(int) * 8);
+ auto i8Ty = ::llvm::Type::getInt8Ty(*::context);
+ auto i8PtrTy = i8Ty->getPointerTo();
+ auto voidTy = ::llvm::Type::getVoidTy(*::context);
+ auto funcTy = ::llvm::FunctionType::get(voidTy, {sizetTy, i8PtrTy, i8PtrTy, intTy}, false);
+ auto func = ::module->getOrInsertFunction("__atomic_store", funcTy);
+ auto size = ::module->getDataLayout().getTypeStoreSize(elTy);
+ auto copy = allocateStackVariable(type);
+ ::builder->CreateStore(V(value), V(copy));
+ ::builder->CreateCall(func, {
+ ::llvm::ConstantInt::get(sizetTy, size),
+ ::builder->CreatePointerCast(V(ptr), i8PtrTy),
+ ::builder->CreatePointerCast(V(copy), i8PtrTy),
+ ::llvm::ConstantInt::get(intTy, uint64_t(atomicOrdering(true, memoryOrder))),
+ });
+ }
+ else
+ {
+ auto store = ::builder->Insert(new llvm::StoreInst(V(value), V(ptr), isVolatile, alignment));
+ store->setAtomic(atomicOrdering(atomic, memoryOrder));
+ }
return value;
}