diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 79d93d08b8398..362f9dff7f4a4 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -147,6 +147,7 @@ Changes to the C API -------------------- * Add `LLVMGetOrInsertFunction` to get or insert a function, replacing the combination of `LLVMGetNamedFunction` and `LLVMAddFunction`. +* Add `LLVMBuildAtomicLoad` and `LLVMBuildAtomicStore` to build atomic load and store instructions by specifying the ordering and whether the operation is single-threaded. Changes to the CodeGen infrastructure ------------------------------------- diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h index 3d22f85911e78..b0f7b4c40b793 100644 --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -4905,6 +4905,34 @@ LLVM_C_ABI LLVMValueRef LLVMBuildAtomicCmpXchgSyncScope( LLVMAtomicOrdering SuccessOrdering, LLVMAtomicOrdering FailureOrdering, unsigned SSID); +/** + * Builds an atomic load instruction. + * + * This is similar to LLVMBuildLoad2, but allows specifying the atomic + * ordering and whether the operation is single-threaded. + * + * @see llvm::IRBuilder::CreateLoad() + * @see llvm::LoadInst::setAtomic() + */ +LLVM_C_ABI LLVMValueRef LLVMBuildAtomicLoad( + LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Source, const char *Name, + LLVMAtomicOrdering Order, LLVMBool SingleThread); + +/** + * Builds an atomic store instruction. + * + * This is similar to LLVMBuildStore, but allows specifying the atomic + * ordering and whether the operation is single-threaded. + * + * @see llvm::IRBuilder::CreateStore() + * @see llvm::StoreInst::setAtomic() + */ +LLVM_C_ABI LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B, + LLVMValueRef V, + LLVMValueRef Target, + LLVMAtomicOrdering Order, + LLVMBool SingleThread); + /** * Get the number of elements in the mask of a ShuffleVector instruction. */ diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index 3f1cc1e4e6d0e..7fcc7ae63f1fb 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -4440,6 +4440,26 @@ LLVMValueRef LLVMBuildAtomicCmpXchgSyncScope(LLVMBuilderRef B, LLVMValueRef Ptr, mapFromLLVMOrdering(FailureOrdering), SSID)); } +LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, LLVMTypeRef Ty, + LLVMValueRef Source, const char *Name, + LLVMAtomicOrdering Order, + LLVMBool SingleThread) { + LoadInst *LI = unwrap(B)->CreateLoad(unwrap(Ty), unwrap(Source), Name); + LI->setAtomic(mapFromLLVMOrdering(Order), + SingleThread ? SyncScope::SingleThread : SyncScope::System); + return wrap(LI); +} + +LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B, LLVMValueRef V, + LLVMValueRef Target, + LLVMAtomicOrdering Order, + LLVMBool SingleThread) { + StoreInst *SI = unwrap(B)->CreateStore(unwrap(V), unwrap(Target)); + SI->setAtomic(mapFromLLVMOrdering(Order), + SingleThread ? SyncScope::SingleThread : SyncScope::System); + return wrap(SI); +} + unsigned LLVMGetNumMaskElements(LLVMValueRef SVInst) { Value *P = unwrap(SVInst); ShuffleVectorInst *I = cast(P); diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp index fe9e7e8228490..1d030309a9a25 100644 --- a/llvm/unittests/IR/InstructionsTest.cpp +++ b/llvm/unittests/IR/InstructionsTest.cpp @@ -1933,5 +1933,48 @@ TEST(InstructionsTest, StripAndAccumulateConstantOffset) { EXPECT_TRUE(Offset.isZero()); } +TEST(FunctionTest, BuildAtomicStoreAndLoad) { + LLVMContext Ctx; + Module M("test", Ctx); + Type *Int32Ty = Type::getInt32Ty(Ctx); + FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), false); + Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, "F", &M); + BasicBlock *BB = BasicBlock::Create(Ctx, "entry", F); + IRBuilder<> Builder(BB); + + AllocaInst *Target = Builder.CreateAlloca(Int32Ty); + Constant *V = ConstantInt::get(Int32Ty, 42); + + // Atomic store + StoreInst *Store = cast( + unwrap(LLVMBuildAtomicStore(wrap(&Builder), wrap(V), wrap(Target), + LLVMAtomicOrderingRelease, false))); + EXPECT_TRUE(Store->isAtomic()); + EXPECT_EQ(Store->getOrdering(), AtomicOrdering::Release); + EXPECT_EQ(Store->getSyncScopeID(), SyncScope::System); + + Store = cast(unwrap( + LLVMBuildAtomicStore(wrap(&Builder), wrap(V), wrap(Target), + LLVMAtomicOrderingSequentiallyConsistent, true))); + EXPECT_TRUE(Store->isAtomic()); + EXPECT_EQ(Store->getOrdering(), AtomicOrdering::SequentiallyConsistent); + EXPECT_EQ(Store->getSyncScopeID(), SyncScope::SingleThread); + + // Atomic load + LoadInst *Load = cast( + unwrap(LLVMBuildAtomicLoad(wrap(&Builder), wrap(Int32Ty), wrap(Target), + "aload", LLVMAtomicOrderingAcquire, false))); + EXPECT_TRUE(Load->isAtomic()); + EXPECT_EQ(Load->getOrdering(), AtomicOrdering::Acquire); + EXPECT_EQ(Load->getSyncScopeID(), SyncScope::System); + + Load = cast(unwrap( + LLVMBuildAtomicLoad(wrap(&Builder), wrap(Int32Ty), wrap(Target), "aload", + LLVMAtomicOrderingSequentiallyConsistent, true))); + EXPECT_TRUE(Load->isAtomic()); + EXPECT_EQ(Load->getOrdering(), AtomicOrdering::SequentiallyConsistent); + EXPECT_EQ(Load->getSyncScopeID(), SyncScope::SingleThread); +} + } // end anonymous namespace } // end namespace llvm