Skip to content

Conversation

AMS21
Copy link
Contributor

@AMS21 AMS21 commented Oct 8, 2025

Adds LLVMBuildAtomicLoad and LLVMBuildAtomicStore functions originally from rustc. rustc LLVMRustBuildAtomicLoad, rustc LLVMRustBuildAtomicStore

Unlike the original I add the option to specify whether the operation is single-threaded similar to how other LLVMBuildAtomic functions do in LLVM-C.

@AMS21 AMS21 requested a review from nikic as a code owner October 8, 2025 10:16
@llvmbot llvmbot added the llvm:ir label Oct 8, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 8, 2025

@llvm/pr-subscribers-llvm-ir

Author: None (AMS21)

Changes

Adds LLVMBuildAtomicLoad and LLVMBuildAtomicStore functions originally from rustc. rustc LLVMRustBuildAtomicLoad, rustc LLVMRustBuildAtomicStore

Unlike the original I add the option to specify whether the operation is single-threaded similar to how other LLVMBuildAtomic functions do in LLVM-C.


Full diff: https://github.com/llvm/llvm-project/pull/162450.diff

4 Files Affected:

  • (modified) llvm/docs/ReleaseNotes.md (+1)
  • (modified) llvm/include/llvm-c/Core.h (+28)
  • (modified) llvm/lib/IR/Core.cpp (+20)
  • (modified) llvm/unittests/IR/InstructionsTest.cpp (+43)
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<ShuffleVectorInst>(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<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

Copy link

github-actions bot commented Oct 8, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions h,cpp -- llvm/include/llvm-c/Core.h llvm/lib/IR/Core.cpp llvm/unittests/IR/InstructionsTest.cpp

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index b0f7b4c40..941875509 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -4914,9 +4914,11 @@ LLVM_C_ABI LLVMValueRef LLVMBuildAtomicCmpXchgSyncScope(
  * @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);
+LLVM_C_ABI LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, LLVMTypeRef Ty,
+                                            LLVMValueRef Source,
+                                            const char *Name,
+                                            LLVMAtomicOrdering Order,
+                                            LLVMBool SingleThread);
 
 /**
  * Builds an atomic store instruction.
@@ -4927,11 +4929,10 @@ LLVM_C_ABI LLVMValueRef LLVMBuildAtomicLoad(
  * @see llvm::IRBuilder::CreateStore()
  * @see llvm::StoreInst::setAtomic()
  */
-LLVM_C_ABI LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B,
-                                                 LLVMValueRef V,
-                                                 LLVMValueRef Target,
-                                                 LLVMAtomicOrdering Order,
-                                                 LLVMBool SingleThread);
+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 7fcc7ae63..aaccdd4a4 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -4451,9 +4451,8 @@ LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, LLVMTypeRef Ty,
 }
 
 LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B, LLVMValueRef V,
-                                      LLVMValueRef Target,
-                                      LLVMAtomicOrdering Order,
-                                      LLVMBool SingleThread) {
+                                  LLVMValueRef Target, LLVMAtomicOrdering Order,
+                                  LLVMBool SingleThread) {
   StoreInst *SI = unwrap(B)->CreateStore(unwrap(V), unwrap(Target));
   SI->setAtomic(mapFromLLVMOrdering(Order),
                 SingleThread ? SyncScope::SingleThread : SyncScope::System);

@nikic
Copy link
Contributor

nikic commented Oct 8, 2025

Hm, do we really need these? Aren't these just combinations of LLVMBuildLoad2/LLVMBuildStore + LLVMSetOrdering (+ LLVMSetAtomicSingleThread if necessary)?

The calling code already sets the alignment separately: https://github.com/rust-lang/rust/blob/5767910cbcc9d199bf261a468574d45aa3857599/compiler/rustc_codegen_llvm/src/builder.rs#L649-L650 So I don't think there is a strong reason to integrate setting the ordering into one C API call.

@AMS21
Copy link
Contributor Author

AMS21 commented Oct 8, 2025

Hm, do we really need these? Aren't these just combinations of LLVMBuildLoad2/LLVMBuildStore + LLVMSetOrdering (+ LLVMSetAtomicSingleThread if necessary)?

The calling code already sets the alignment separately: https://github.com/rust-lang/rust/blob/5767910cbcc9d199bf261a468574d45aa3857599/compiler/rustc_codegen_llvm/src/builder.rs#L649-L650 So I don't think there is a strong reason to integrate setting the ordering into one C API call.

Alright I guess then it would be better to refactor this on the rustc side.
Thanks for the quick response :)

@AMS21 AMS21 closed this Oct 8, 2025
@AMS21 AMS21 deleted the upstream_build_atomic_load_store branch October 8, 2025 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants