Commit 2fa1dad2 by Ben Clayton

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: 's avatarChris Forbes <chrisforbes@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent a0b3a026
...@@ -1391,11 +1391,36 @@ namespace rr ...@@ -1391,11 +1391,36 @@ namespace rr
{ {
auto elTy = T(type); auto elTy = T(type);
ASSERT(V(ptr)->getType()->getContainedType(0) == elTy); ASSERT(V(ptr)->getType()->getContainedType(0) == elTy);
if (atomic && !(elTy->isIntegerTy() || elTy->isPointerTy() || elTy->isFloatTy()))
if (!atomic)
{
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())
{ {
// atomic load operand must have integer, pointer, or floating point type // LLVM claims to support atomic loads of float types as
// Fall back to using: // above, but certain backends cannot deal with this.
// void __atomic_load(size_t size, void *ptr, void *ret, int ordering) // 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 sizetTy = ::llvm::IntegerType::get(*::context, sizeof(size_t) * 8);
auto intTy = ::llvm::IntegerType::get(*::context, sizeof(int) * 8); auto intTy = ::llvm::IntegerType::get(*::context, sizeof(int) * 8);
auto i8Ty = ::llvm::Type::getInt8Ty(*::context); auto i8Ty = ::llvm::Type::getInt8Ty(*::context);
...@@ -1413,12 +1438,6 @@ namespace rr ...@@ -1413,12 +1438,6 @@ namespace rr
}); });
return V(::builder->CreateLoad(V(out))); 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: default:
UNREACHABLE("asInternalType(type): %d", int(asInternalType(type))); UNREACHABLE("asInternalType(type): %d", int(asInternalType(type)));
...@@ -1456,11 +1475,34 @@ namespace rr ...@@ -1456,11 +1475,34 @@ namespace rr
{ {
auto elTy = T(type); auto elTy = T(type);
ASSERT(V(ptr)->getType()->getContainedType(0) == elTy); ASSERT(V(ptr)->getType()->getContainedType(0) == elTy);
if (atomic && !(elTy->isIntegerTy() || elTy->isPointerTy() || elTy->isFloatTy()))
if (!atomic)
{
::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())
{ {
// atomic store operand must have integer, pointer, or floating point type // LLVM claims to support atomic stores of float types as
// Fall back to using: // above, but certain backends cannot deal with this.
// void __atomic_store(size_t size, void *ptr, void *val, int ordering) // 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 sizetTy = ::llvm::IntegerType::get(*::context, sizeof(size_t) * 8);
auto intTy = ::llvm::IntegerType::get(*::context, sizeof(int) * 8); auto intTy = ::llvm::IntegerType::get(*::context, sizeof(int) * 8);
auto i8Ty = ::llvm::Type::getInt8Ty(*::context); auto i8Ty = ::llvm::Type::getInt8Ty(*::context);
...@@ -1478,11 +1520,6 @@ namespace rr ...@@ -1478,11 +1520,6 @@ namespace rr
::llvm::ConstantInt::get(intTy, uint64_t(atomicOrdering(true, memoryOrder))), ::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; return value;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment