LLVMReactor: Perform atomic load / stores of floats as ints.
LLVM claims to support atomic loads and stores of integers, pointers and floating point types, but certain backends cannot deal with floats.
Mimic what Clang does - bitcast to/from an equal width integer.
Bug: b/136037244
Change-Id: I40167279de96f586414f4fb406bf100432a39abf
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/33408
Kokoro-Presubmit: kokoro <noreply+kokoro@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/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index d1c6eb2..5d8afa2 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -1391,11 +1391,36 @@
{
auto elTy = T(type);
ASSERT(V(ptr)->getType()->getContainedType(0) == elTy);
- if (atomic && !(elTy->isIntegerTy() || elTy->isPointerTy() || elTy->isFloatTy()))
+
+ if (!atomic)
{
- // 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)
+ return V(::builder->CreateAlignedLoad(V(ptr), alignment, isVolatile));
+ }
+ else if (elTy->isIntegerTy() || elTy->isPointerTy())
+ {
+ // Integers and pointers can be atomically loaded by setting
+ // the ordering constraint on the load instruction.
+ auto load = ::builder->CreateAlignedLoad(V(ptr), alignment, isVolatile);
+ load->setAtomic(atomicOrdering(atomic, memoryOrder));
+ return V(load);
+ }
+ else if (elTy->isFloatTy() || elTy->isDoubleTy())
+ {
+ // LLVM claims to support atomic loads of float types as
+ // above, but certain backends cannot deal with this.
+ // Load as an integer and bitcast. See b/136037244.
+ auto size = ::module->getDataLayout().getTypeStoreSize(elTy);
+ auto elAsIntTy = ::llvm::IntegerType::get(*::context, size * 8);
+ auto ptrCast = ::builder->CreatePointerCast(V(ptr), elAsIntTy->getPointerTo());
+ auto load = ::builder->CreateAlignedLoad(ptrCast, alignment, isVolatile);
+ load->setAtomic(atomicOrdering(atomic, memoryOrder));
+ auto loadCast = ::builder->CreateBitCast(load, elTy);
+ return V(loadCast);
+ }
+ else
+ {
+ // More exotic types require falling back to the extern:
+ // 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);
@@ -1413,12 +1438,6 @@
});
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)));
@@ -1456,11 +1475,34 @@
{
auto elTy = T(type);
ASSERT(V(ptr)->getType()->getContainedType(0) == elTy);
- if (atomic && !(elTy->isIntegerTy() || elTy->isPointerTy() || elTy->isFloatTy()))
+
+ if (!atomic)
{
- // 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)
+ ::builder->CreateAlignedStore(V(value), V(ptr), alignment, isVolatile);
+ }
+ else if (elTy->isIntegerTy() || elTy->isPointerTy())
+ {
+ // Integers and pointers can be atomically stored by setting
+ // the ordering constraint on the store instruction.
+ auto store = ::builder->CreateAlignedStore(V(value), V(ptr), alignment, isVolatile);
+ store->setAtomic(atomicOrdering(atomic, memoryOrder));
+ }
+ else if (elTy->isFloatTy() || elTy->isDoubleTy())
+ {
+ // LLVM claims to support atomic stores of float types as
+ // above, but certain backends cannot deal with this.
+ // Store as an bitcast integer. See b/136037244.
+ auto size = ::module->getDataLayout().getTypeStoreSize(elTy);
+ auto elAsIntTy = ::llvm::IntegerType::get(*::context, size * 8);
+ auto valCast = ::builder->CreateBitCast(V(value), elAsIntTy);
+ auto ptrCast = ::builder->CreatePointerCast(V(ptr), elAsIntTy->getPointerTo());
+ auto store = ::builder->CreateAlignedStore(valCast, ptrCast, alignment, isVolatile);
+ store->setAtomic(atomicOrdering(atomic, memoryOrder));
+ }
+ else
+ {
+ // More exotic types require falling back to the extern:
+ // 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);
@@ -1478,11 +1520,6 @@
::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;
}