Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------------------------------------
Expand Down
28 changes: 28 additions & 0 deletions llvm/include/llvm-c/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
20 changes: 20 additions & 0 deletions llvm/lib/IR/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<ShuffleVectorInst>(P);
Expand Down
43 changes: 43 additions & 0 deletions llvm/unittests/IR/InstructionsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<StoreInst>(
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<StoreInst>(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<LoadInst>(
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<LoadInst>(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
Loading