[llvm] [LLVM] Add a C API for creating instructions with custom syncscopes. (PR #104775)

Tim Besard via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 20 00:59:57 PDT 2024


https://github.com/maleadt updated https://github.com/llvm/llvm-project/pull/104775

>From a86400d00a236670634fd171d80a0c5a41f39c8c Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Mon, 19 Aug 2024 14:45:08 +0200
Subject: [PATCH 1/4] [LLVM] Add a C API for creating instructions with custom
 syncscopes.

---
 llvm/docs/ReleaseNotes.rst        | 10 ++++
 llvm/include/llvm-c/Core.h        | 43 +++++++++++++++
 llvm/lib/IR/Core.cpp              | 91 ++++++++++++++++++++++++++-----
 llvm/test/Bindings/llvm-c/echo.ll | 18 ++++--
 4 files changed, 144 insertions(+), 18 deletions(-)

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index d40bb2682f9ad8..3ab9e109704461 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -163,6 +163,16 @@ Changes to the C API
 * It is now also possible to run the new pass manager on a single function, by calling
   ``LLVMRunPassesOnFunction`` instead of ``LLVMRunPasses``.
 
+* Support for creating instructions with custom synchronization scopes has been added:
+
+  * ``LLVMGetSyncScopeID`` and ``LLVMGetSyncScopeIDInContext`` to map a synchronization
+    scope name to an ID, and ``LLVMGetSyncScopeName`` to map an ID back to a name.
+  * ``LLVMBuildFenceSyncScope``, ``LLVMBuildAtomicRMWSyncScope`` and
+    ``LLVMBuildAtomicCmpXchgSyncScope`` versions of the existing builder functions
+    with an additional synchronization scope ID parameter.
+  * ``LLVMGetAtomicSyncScopeID`` and ``LLVMSetAtomicSyncScopeID`` to get and set the
+    synchronization scope of any atomic instruction.
+
 Changes to the CodeGen infrastructure
 -------------------------------------
 
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 7d2e7c95520761..6c8b497c15dd70 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -646,6 +646,26 @@ unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char *Name,
                                   unsigned SLen);
 unsigned LLVMGetMDKindID(const char *Name, unsigned SLen);
 
+/**
+ * Maps a synchronization scope name to a ID unique within this context.
+ */
+unsigned LLVMGetSyncScopeIDInContext(LLVMContextRef C, const char *Name,
+                                     unsigned SLen);
+
+/**
+ * Maps a synchronization scope name to a unique ID.
+ *
+ * This is equivalent to calling LLVMGetSyncScopeIDInContext with
+ * LLVMGetGlobalContext() as the context parameter.
+ */
+unsigned LLVMGetSyncScopeID(const char *Name, unsigned SLen);
+
+/**
+ * Maps a synchronization scope ID to its name.
+ */
+const char *LLVMGetSyncScopeName(LLVMContextRef C, unsigned ID,
+                                 unsigned *Length);
+
 /**
  * Return an unique id given the name of a enum attribute,
  * or 0 if no attribute by that name exists.
@@ -4578,15 +4598,28 @@ LLVMValueRef LLVMBuildPtrDiff2(LLVMBuilderRef, LLVMTypeRef ElemTy,
                                const char *Name);
 LLVMValueRef LLVMBuildFence(LLVMBuilderRef B, LLVMAtomicOrdering ordering,
                             LLVMBool singleThread, const char *Name);
+LLVMValueRef LLVMBuildFenceSyncScope(LLVMBuilderRef B,
+                                     LLVMAtomicOrdering ordering, unsigned SSID,
+                                     const char *Name);
 LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B, LLVMAtomicRMWBinOp op,
                                 LLVMValueRef PTR, LLVMValueRef Val,
                                 LLVMAtomicOrdering ordering,
                                 LLVMBool singleThread);
+LLVMValueRef LLVMBuildAtomicRMWSyncScope(LLVMBuilderRef B,
+                                         LLVMAtomicRMWBinOp op,
+                                         LLVMValueRef PTR, LLVMValueRef Val,
+                                         LLVMAtomicOrdering ordering,
+                                         unsigned SSID);
 LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr,
                                     LLVMValueRef Cmp, LLVMValueRef New,
                                     LLVMAtomicOrdering SuccessOrdering,
                                     LLVMAtomicOrdering FailureOrdering,
                                     LLVMBool SingleThread);
+LLVMValueRef LLVMBuildAtomicCmpXchgSyncScope(LLVMBuilderRef B, LLVMValueRef Ptr,
+                                             LLVMValueRef Cmp, LLVMValueRef New,
+                                             LLVMAtomicOrdering SuccessOrdering,
+                                             LLVMAtomicOrdering FailureOrdering,
+                                             unsigned SSID);
 
 /**
  * Get the number of elements in the mask of a ShuffleVector instruction.
@@ -4611,6 +4644,16 @@ int LLVMGetMaskValue(LLVMValueRef ShuffleVectorInst, unsigned Elt);
 LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst);
 void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool SingleThread);
 
+/**
+ * Returns the synchronization scope ID of an atomic instruction
+ */
+unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst);
+
+/**
+ * Sets the synchronization scope ID of an atomic instruction.
+ */
+void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID);
+
 LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst);
 void LLVMSetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst,
                                    LLVMAtomicOrdering Ordering);
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index dcad76ee8491dd..c8362a236d8e6d 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -146,6 +146,24 @@ unsigned LLVMGetMDKindID(const char *Name, unsigned SLen) {
   return LLVMGetMDKindIDInContext(LLVMGetGlobalContext(), Name, SLen);
 }
 
+unsigned LLVMGetSyncScopeIDInContext(LLVMContextRef C, const char *Name,
+                                     unsigned SLen) {
+  return unwrap(C)->getOrInsertSyncScopeID(StringRef(Name, SLen));
+}
+
+unsigned LLVMGetSyncScopeID(const char *Name, unsigned SLen) {
+  return LLVMGetSyncScopeIDInContext(LLVMGetGlobalContext(), Name, SLen);
+}
+
+const char *LLVMGetSyncScopeName(LLVMContextRef C, unsigned ID,
+                                 unsigned *Length) {
+  SmallVector<StringRef> SSNs;
+  unwrap(C)->getSyncScopeNames(SSNs);
+  StringRef Name = SSNs[ID].empty() ? "system" : SSNs[ID];
+  *Length = Name.size();
+  return Name.data();
+}
+
 unsigned LLVMGetEnumAttributeKindForName(const char *Name, size_t SLen) {
   return Attribute::getAttrKindFromName(StringRef(Name, SLen));
 }
@@ -3949,8 +3967,6 @@ static LLVMAtomicRMWBinOp mapToLLVMRMWBinOp(AtomicRMWInst::BinOp BinOp) {
   llvm_unreachable("Invalid AtomicRMWBinOp value!");
 }
 
-// TODO: Should this and other atomic instructions support building with
-// "syncscope"?
 LLVMValueRef LLVMBuildFence(LLVMBuilderRef B, LLVMAtomicOrdering Ordering,
                             LLVMBool isSingleThread, const char *Name) {
   return wrap(
@@ -3960,6 +3976,13 @@ LLVMValueRef LLVMBuildFence(LLVMBuilderRef B, LLVMAtomicOrdering Ordering,
                            Name));
 }
 
+LLVMValueRef LLVMBuildFenceSyncScope(LLVMBuilderRef B,
+                                     LLVMAtomicOrdering Ordering, unsigned SSID,
+                                     const char *Name) {
+  return wrap(
+      unwrap(B)->CreateFence(mapFromLLVMOrdering(Ordering), SSID, Name));
+}
+
 LLVMValueRef LLVMBuildGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
                            LLVMValueRef Pointer, LLVMValueRef *Indices,
                            unsigned NumIndices, const char *Name) {
@@ -4309,6 +4332,22 @@ LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B,LLVMAtomicRMWBinOp op,
       singleThread ? SyncScope::SingleThread : SyncScope::System));
 }
 
+LLVMValueRef LLVMBuildAtomicRMWSyncScope(LLVMBuilderRef B,
+                                         LLVMAtomicRMWBinOp op,
+                                         LLVMValueRef PTR, LLVMValueRef Val,
+                                         LLVMAtomicOrdering ordering,
+                                         unsigned SSID) {
+  AtomicRMWInst::BinOp intop = mapFromLLVMRMWBinOp(op);
+
+  SmallVector<StringRef> SSNs;
+  unwrap(B)->getContext().getSyncScopeNames(SSNs);
+  assert(SSID < SSNs.size() && "Invalid SyncScopeID");
+
+  return wrap(unwrap(B)->CreateAtomicRMW(intop, unwrap(PTR), unwrap(Val),
+                                         MaybeAlign(),
+                                         mapFromLLVMOrdering(ordering), SSID));
+}
+
 LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr,
                                     LLVMValueRef Cmp, LLVMValueRef New,
                                     LLVMAtomicOrdering SuccessOrdering,
@@ -4322,6 +4361,17 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr,
       singleThread ? SyncScope::SingleThread : SyncScope::System));
 }
 
+LLVMValueRef LLVMBuildAtomicCmpXchgSyncScope(LLVMBuilderRef B, LLVMValueRef Ptr,
+                                             LLVMValueRef Cmp, LLVMValueRef New,
+                                             LLVMAtomicOrdering SuccessOrdering,
+                                             LLVMAtomicOrdering FailureOrdering,
+                                             unsigned SSID) {
+  return wrap(unwrap(B)->CreateAtomicCmpXchg(
+      unwrap(Ptr), unwrap(Cmp), unwrap(New), MaybeAlign(),
+      mapFromLLVMOrdering(SuccessOrdering),
+      mapFromLLVMOrdering(FailureOrdering), SSID));
+}
+
 unsigned LLVMGetNumMaskElements(LLVMValueRef SVInst) {
   Value *P = unwrap(SVInst);
   ShuffleVectorInst *I = cast<ShuffleVectorInst>(P);
@@ -4336,25 +4386,29 @@ int LLVMGetMaskValue(LLVMValueRef SVInst, unsigned Elt) {
 
 int LLVMGetUndefMaskElem(void) { return PoisonMaskElem; }
 
-LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) {
-  Value *P = unwrap(AtomicInst);
-
+static unsigned getAtomicSyncScopeID(Value *P) {
   if (AtomicRMWInst *I = dyn_cast<AtomicRMWInst>(P))
-    return I->getSyncScopeID() == SyncScope::SingleThread;
+    return I->getSyncScopeID();
   else if (FenceInst *FI = dyn_cast<FenceInst>(P))
-    return FI->getSyncScopeID() == SyncScope::SingleThread;
+    return FI->getSyncScopeID();
   else if (StoreInst *SI = dyn_cast<StoreInst>(P))
-    return SI->getSyncScopeID() == SyncScope::SingleThread;
+    return SI->getSyncScopeID();
   else if (LoadInst *LI = dyn_cast<LoadInst>(P))
-    return LI->getSyncScopeID() == SyncScope::SingleThread;
-  return cast<AtomicCmpXchgInst>(P)->getSyncScopeID() ==
-             SyncScope::SingleThread;
+    return LI->getSyncScopeID();
+  return cast<AtomicCmpXchgInst>(P)->getSyncScopeID();
 }
 
-void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) {
+LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) {
   Value *P = unwrap(AtomicInst);
-  SyncScope::ID SSID = NewValue ? SyncScope::SingleThread : SyncScope::System;
+  return getAtomicSyncScopeID(P) == SyncScope::SingleThread;
+}
+
+unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) {
+  Value *P = unwrap(AtomicInst);
+  return getAtomicSyncScopeID(P);
+}
 
+static void setAtomicSyncScopeID(Value *P, unsigned SSID) {
   if (AtomicRMWInst *I = dyn_cast<AtomicRMWInst>(P))
     return I->setSyncScopeID(SSID);
   else if (FenceInst *FI = dyn_cast<FenceInst>(P))
@@ -4366,6 +4420,17 @@ void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) {
   return cast<AtomicCmpXchgInst>(P)->setSyncScopeID(SSID);
 }
 
+void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) {
+  Value *P = unwrap(AtomicInst);
+  SyncScope::ID SSID = NewValue ? SyncScope::SingleThread : SyncScope::System;
+  setAtomicSyncScopeID(P, SSID);
+}
+
+void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID) {
+  Value *P = unwrap(AtomicInst);
+  setAtomicSyncScopeID(P, SSID);
+}
+
 LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst)  {
   Value *P = unwrap(CmpXchgInst);
   return mapToLLVMOrdering(cast<AtomicCmpXchgInst>(P)->getSuccessOrdering());
diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
index 45e3d0357ebdf2..c4b932034b501a 100644
--- a/llvm/test/Bindings/llvm-c/echo.ll
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -216,15 +216,23 @@ define void @memops(ptr %ptr) {
   %b = load volatile i8, ptr %ptr
   %c = load i8, ptr %ptr, align 8
   %d = load atomic i8, ptr %ptr acquire, align 32
+  %e = load atomic i8, ptr %ptr syncscope("singlethread") acquire, align 32
   store i8 0, ptr %ptr
   store volatile i8 0, ptr %ptr
   store i8 0, ptr %ptr, align 8
   store atomic i8 0, ptr %ptr release, align 32
-  %e = atomicrmw add ptr %ptr, i8 0 monotonic, align 1
-  %f = atomicrmw volatile xchg ptr %ptr, i8 0 acq_rel, align 8
-  %g = cmpxchg ptr %ptr, i8 1, i8 2 seq_cst acquire, align 1
-  %h = cmpxchg weak ptr %ptr, i8 1, i8 2 seq_cst acquire, align 8
-  %i = cmpxchg volatile ptr %ptr, i8 1, i8 2 monotonic monotonic, align 16
+  store atomic i8 0, ptr %ptr syncscope("singlethread") release, align 32
+  %f = atomicrmw add ptr %ptr, i8 0 monotonic, align 1
+  %g = atomicrmw volatile xchg ptr %ptr, i8 0 acq_rel, align 8
+  %h = atomicrmw volatile xchg ptr %ptr, i8 0 syncscope("singlethread") acq_rel, align 8
+  %i = atomicrmw volatile xchg ptr %ptr, i8 0 syncscope("agent") acq_rel, align 8
+  %j = cmpxchg ptr %ptr, i8 1, i8 2 seq_cst acquire, align 1
+  %k = cmpxchg weak ptr %ptr, i8 1, i8 2 seq_cst acquire, align 8
+  %l = cmpxchg volatile ptr %ptr, i8 1, i8 2 monotonic monotonic, align 16
+  %m = cmpxchg volatile ptr %ptr, i8 1, i8 2 syncscope("singlethread") monotonic monotonic, align 16
+  %n = cmpxchg volatile ptr %ptr, i8 1, i8 2 syncscope("agent") monotonic monotonic, align 16
+  fence syncscope("singlethread") acquire
+  fence syncscope("agent") acquire
   ret void
 }
 

>From 0b9f0753083861ae72956ebef88f1b5e22774f0c Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Mon, 19 Aug 2024 14:45:51 +0200
Subject: [PATCH 2/4] Fix llvm-c-text to use the same context when cloning
 instructions.

---
 llvm/tools/llvm-c-test/attributes.c  |  4 +--
 llvm/tools/llvm-c-test/echo.cpp      | 40 +++++++++++++++++++++-------
 llvm/tools/llvm-c-test/llvm-c-test.h |  2 +-
 llvm/tools/llvm-c-test/module.c      | 17 ++++++------
 4 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/llvm/tools/llvm-c-test/attributes.c b/llvm/tools/llvm-c-test/attributes.c
index 487769f94dbcba..088684cd3ed362 100644
--- a/llvm/tools/llvm-c-test/attributes.c
+++ b/llvm/tools/llvm-c-test/attributes.c
@@ -20,7 +20,7 @@
 int llvm_test_function_attributes(void) {
   LLVMEnablePrettyStackTrace();
 
-  LLVMModuleRef M = llvm_load_module(false, true);
+  LLVMModuleRef M = llvm_load_module(LLVMGetGlobalContext(), false, true);
 
   LLVMValueRef F = LLVMGetFirstFunction(M);
   while (F) {
@@ -49,7 +49,7 @@ int llvm_test_function_attributes(void) {
 int llvm_test_callsite_attributes(void) {
   LLVMEnablePrettyStackTrace();
 
-  LLVMModuleRef M = llvm_load_module(false, true);
+  LLVMModuleRef M = llvm_load_module(LLVMGetGlobalContext(), false, true);
 
   LLVMValueRef F = LLVMGetFirstFunction(M);
   while (F) {
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 1e78637bf47ca3..696c6d6aa2fe0d 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -520,6 +520,7 @@ struct FunCloner {
     check_value_kind(Src, LLVMInstructionValueKind);
     if (!LLVMIsAInstruction(Src))
       report_fatal_error("Expected an instruction");
+    LLVMContextRef Ctx = LLVMGetTypeContext(LLVMTypeOf(Src));
 
     size_t NameLen;
     const char *Name = LLVMGetValueName2(Src, &NameLen);
@@ -754,7 +755,11 @@ struct FunCloner {
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetOrdering(Dst, LLVMGetOrdering(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
-        LLVMSetAtomicSingleThread(Dst, LLVMIsAtomicSingleThread(Src));
+        LLVMBool IsAtomicSingleThread = LLVMIsAtomicSingleThread(Src);
+        if (IsAtomicSingleThread)
+          LLVMSetAtomicSingleThread(Dst, IsAtomicSingleThread);
+        else
+          LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src));
         break;
       }
       case LLVMStore: {
@@ -764,7 +769,11 @@ struct FunCloner {
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetOrdering(Dst, LLVMGetOrdering(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
-        LLVMSetAtomicSingleThread(Dst, LLVMIsAtomicSingleThread(Src));
+        LLVMBool IsAtomicSingleThread = LLVMIsAtomicSingleThread(Src);
+        if (IsAtomicSingleThread)
+          LLVMSetAtomicSingleThread(Dst, IsAtomicSingleThread);
+        else
+          LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src));
         break;
       }
       case LLVMGetElementPtr: {
@@ -786,7 +795,11 @@ struct FunCloner {
         LLVMAtomicRMWBinOp BinOp = LLVMGetAtomicRMWBinOp(Src);
         LLVMAtomicOrdering Ord = LLVMGetOrdering(Src);
         LLVMBool SingleThread = LLVMIsAtomicSingleThread(Src);
-        Dst = LLVMBuildAtomicRMW(Builder, BinOp, Ptr, Val, Ord, SingleThread);
+        if (SingleThread)
+          Dst = LLVMBuildAtomicRMW(Builder, BinOp, Ptr, Val, Ord, SingleThread);
+        else
+          Dst = LLVMBuildAtomicRMWSyncScope(Builder, BinOp, Ptr, Val, Ord,
+                                            LLVMGetAtomicSyncScopeID(Src));
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
         LLVMSetValueName2(Dst, Name, NameLen);
@@ -799,9 +812,13 @@ struct FunCloner {
         LLVMAtomicOrdering Succ = LLVMGetCmpXchgSuccessOrdering(Src);
         LLVMAtomicOrdering Fail = LLVMGetCmpXchgFailureOrdering(Src);
         LLVMBool SingleThread = LLVMIsAtomicSingleThread(Src);
-
-        Dst = LLVMBuildAtomicCmpXchg(Builder, Ptr, Cmp, New, Succ, Fail,
-                                     SingleThread);
+        if (SingleThread)
+          Dst = LLVMBuildAtomicCmpXchg(Builder, Ptr, Cmp, New, Succ, Fail,
+                                       SingleThread);
+        else
+          Dst = LLVMBuildAtomicCmpXchgSyncScope(Builder, Ptr, Cmp, New, Succ,
+                                                Fail,
+                                                LLVMGetAtomicSyncScopeID(Src));
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
         LLVMSetWeak(Dst, LLVMGetWeak(Src));
@@ -993,7 +1010,11 @@ struct FunCloner {
       case LLVMFence: {
         LLVMAtomicOrdering Ordering = LLVMGetOrdering(Src);
         LLVMBool IsSingleThreaded = LLVMIsAtomicSingleThread(Src);
-        Dst = LLVMBuildFence(Builder, Ordering, IsSingleThreaded, Name);
+        if (IsSingleThreaded)
+          Dst = LLVMBuildFence(Builder, Ordering, IsSingleThreaded, Name);
+        else
+          Dst = LLVMBuildFenceSyncScope(Builder, Ordering,
+                                        LLVMGetAtomicSyncScopeID(Src), Name);
         break;
       }
       case LLVMZExt: {
@@ -1059,7 +1080,6 @@ struct FunCloner {
     if (LLVMCanValueUseFastMathFlags(Src))
       LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
 
-    auto Ctx = LLVMGetModuleContext(M);
     size_t NumMetadataEntries;
     auto *AllMetadata =
         LLVMInstructionGetAllMetadataOtherThanDebugLoc(Src,
@@ -1609,12 +1629,12 @@ static void clone_symbols(LLVMModuleRef Src, LLVMModuleRef M) {
 int llvm_echo(void) {
   LLVMEnablePrettyStackTrace();
 
-  LLVMModuleRef Src = llvm_load_module(false, true);
+  LLVMContextRef Ctx = LLVMContextCreate();
+  LLVMModuleRef Src = llvm_load_module(Ctx, false, true);
   size_t SourceFileLen;
   const char *SourceFileName = LLVMGetSourceFileName(Src, &SourceFileLen);
   size_t ModuleIdentLen;
   const char *ModuleName = LLVMGetModuleIdentifier(Src, &ModuleIdentLen);
-  LLVMContextRef Ctx = LLVMContextCreate();
   LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleName, Ctx);
 
   LLVMSetSourceFileName(M, SourceFileName, SourceFileLen);
diff --git a/llvm/tools/llvm-c-test/llvm-c-test.h b/llvm/tools/llvm-c-test/llvm-c-test.h
index 00566660257e07..1da6596cd5a8f2 100644
--- a/llvm/tools/llvm-c-test/llvm-c-test.h
+++ b/llvm/tools/llvm-c-test/llvm-c-test.h
@@ -24,7 +24,7 @@ extern "C" {
 void llvm_tokenize_stdin(void (*cb)(char **tokens, int ntokens));
 
 // module.c
-LLVMModuleRef llvm_load_module(bool Lazy, bool New);
+LLVMModuleRef llvm_load_module(LLVMContextRef C, bool Lazy, bool New);
 int llvm_module_dump(bool Lazy, bool New);
 int llvm_module_list_functions(void);
 int llvm_module_list_globals(void);
diff --git a/llvm/tools/llvm-c-test/module.c b/llvm/tools/llvm-c-test/module.c
index 9fc86cfe5404b3..9698f0983d5b63 100644
--- a/llvm/tools/llvm-c-test/module.c
+++ b/llvm/tools/llvm-c-test/module.c
@@ -24,7 +24,7 @@ static void diagnosticHandler(LLVMDiagnosticInfoRef DI, void *C) {
   exit(1);
 }
 
-LLVMModuleRef llvm_load_module(bool Lazy, bool New) {
+LLVMModuleRef llvm_load_module(LLVMContextRef C, bool Lazy, bool New) {
   LLVMMemoryBufferRef MB;
   LLVMModuleRef M;
   char *msg = NULL;
@@ -36,17 +36,16 @@ LLVMModuleRef llvm_load_module(bool Lazy, bool New) {
 
   LLVMBool Ret;
   if (New) {
-    LLVMContextRef C = LLVMGetGlobalContext();
     LLVMContextSetDiagnosticHandler(C, diagnosticHandler, NULL);
     if (Lazy)
-      Ret = LLVMGetBitcodeModule2(MB, &M);
+      Ret = LLVMGetBitcodeModuleInContext2(C, MB, &M);
     else
-      Ret = LLVMParseBitcode2(MB, &M);
+      Ret = LLVMParseBitcodeInContext2(C, MB, &M);
   } else {
     if (Lazy)
-      Ret = LLVMGetBitcodeModule(MB, &M, &msg);
+      Ret = LLVMGetBitcodeModuleInContext(C, MB, &M, &msg);
     else
-      Ret = LLVMParseBitcode(MB, &M, &msg);
+      Ret = LLVMParseBitcodeInContext(C, MB, &M, &msg);
   }
 
   if (Ret) {
@@ -62,7 +61,7 @@ LLVMModuleRef llvm_load_module(bool Lazy, bool New) {
 }
 
 int llvm_module_dump(bool Lazy, bool New) {
-  LLVMModuleRef M = llvm_load_module(Lazy, New);
+  LLVMModuleRef M = llvm_load_module(LLVMGetGlobalContext(), Lazy, New);
 
   char *irstr = LLVMPrintModuleToString(M);
   puts(irstr);
@@ -74,7 +73,7 @@ int llvm_module_dump(bool Lazy, bool New) {
 }
 
 int llvm_module_list_functions(void) {
-  LLVMModuleRef M = llvm_load_module(false, false);
+  LLVMModuleRef M = llvm_load_module(LLVMGetGlobalContext(), false, false);
   LLVMValueRef f;
 
   f = LLVMGetFirstFunction(M);
@@ -115,7 +114,7 @@ int llvm_module_list_functions(void) {
 }
 
 int llvm_module_list_globals(void) {
-  LLVMModuleRef M = llvm_load_module(false, false);
+  LLVMModuleRef M = llvm_load_module(LLVMGetGlobalContext(), false, false);
   LLVMValueRef g;
 
   g = LLVMGetFirstGlobal(M);

>From 0028d86595b6fb23c9cbdd603dfef78437a3f5c8 Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Mon, 19 Aug 2024 16:43:02 +0200
Subject: [PATCH 3/4] Address review comments.

---
 llvm/docs/ReleaseNotes.rst          |  3 +-
 llvm/include/llvm-c/Core.h          | 17 +--------
 llvm/include/llvm/IR/Instructions.h | 19 ++++++++++
 llvm/lib/IR/Core.cpp                | 59 ++++-------------------------
 4 files changed, 28 insertions(+), 70 deletions(-)

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 3ab9e109704461..145b30b1668ea4 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -165,8 +165,7 @@ Changes to the C API
 
 * Support for creating instructions with custom synchronization scopes has been added:
 
-  * ``LLVMGetSyncScopeID`` and ``LLVMGetSyncScopeIDInContext`` to map a synchronization
-    scope name to an ID, and ``LLVMGetSyncScopeName`` to map an ID back to a name.
+  * ``LLVMGetSyncScopeID`` to map a synchronization scope name to an ID
   * ``LLVMBuildFenceSyncScope``, ``LLVMBuildAtomicRMWSyncScope`` and
     ``LLVMBuildAtomicCmpXchgSyncScope`` versions of the existing builder functions
     with an additional synchronization scope ID parameter.
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 6c8b497c15dd70..c7a75ceb244a69 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -649,22 +649,7 @@ unsigned LLVMGetMDKindID(const char *Name, unsigned SLen);
 /**
  * Maps a synchronization scope name to a ID unique within this context.
  */
-unsigned LLVMGetSyncScopeIDInContext(LLVMContextRef C, const char *Name,
-                                     unsigned SLen);
-
-/**
- * Maps a synchronization scope name to a unique ID.
- *
- * This is equivalent to calling LLVMGetSyncScopeIDInContext with
- * LLVMGetGlobalContext() as the context parameter.
- */
-unsigned LLVMGetSyncScopeID(const char *Name, unsigned SLen);
-
-/**
- * Maps a synchronization scope ID to its name.
- */
-const char *LLVMGetSyncScopeName(LLVMContextRef C, unsigned ID,
-                                 unsigned *Length);
+unsigned LLVMGetSyncScopeID(LLVMContextRef C, const char *Name, size_t SLen);
 
 /**
  * Return an unique id given the name of a enum attribute,
diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 968737a843e292..5640a80c22d49f 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -4942,6 +4942,25 @@ inline std::optional<SyncScope::ID> getAtomicSyncScopeID(const Instruction *I) {
   llvm_unreachable("unhandled atomic operation");
 }
 
+/// A helper function that sets an atomic operation's sync scope.
+/// Does nothing if it is not an atomic operation.
+inline void setAtomicSyncScopeID(Instruction *I, SyncScope::ID SSID) {
+  if (!I->isAtomic())
+    return;
+  if (auto *AI = dyn_cast<LoadInst>(I))
+    AI->setSyncScopeID(SSID);
+  else if (auto *AI = dyn_cast<StoreInst>(I))
+    AI->setSyncScopeID(SSID);
+  else if (auto *AI = dyn_cast<FenceInst>(I))
+    AI->setSyncScopeID(SSID);
+  else if (auto *AI = dyn_cast<AtomicCmpXchgInst>(I))
+    AI->setSyncScopeID(SSID);
+  else if (auto *AI = dyn_cast<AtomicRMWInst>(I))
+    AI->setSyncScopeID(SSID);
+  else
+    llvm_unreachable("unhandled atomic operation");
+}
+
 //===----------------------------------------------------------------------===//
 //                              FreezeInst Class
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index c8362a236d8e6d..18cc0354947384 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -24,6 +24,7 @@
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/LegacyPassManager.h"
@@ -146,24 +147,10 @@ unsigned LLVMGetMDKindID(const char *Name, unsigned SLen) {
   return LLVMGetMDKindIDInContext(LLVMGetGlobalContext(), Name, SLen);
 }
 
-unsigned LLVMGetSyncScopeIDInContext(LLVMContextRef C, const char *Name,
-                                     unsigned SLen) {
+unsigned LLVMGetSyncScopeID(LLVMContextRef C, const char *Name, size_t SLen) {
   return unwrap(C)->getOrInsertSyncScopeID(StringRef(Name, SLen));
 }
 
-unsigned LLVMGetSyncScopeID(const char *Name, unsigned SLen) {
-  return LLVMGetSyncScopeIDInContext(LLVMGetGlobalContext(), Name, SLen);
-}
-
-const char *LLVMGetSyncScopeName(LLVMContextRef C, unsigned ID,
-                                 unsigned *Length) {
-  SmallVector<StringRef> SSNs;
-  unwrap(C)->getSyncScopeNames(SSNs);
-  StringRef Name = SSNs[ID].empty() ? "system" : SSNs[ID];
-  *Length = Name.size();
-  return Name.data();
-}
-
 unsigned LLVMGetEnumAttributeKindForName(const char *Name, size_t SLen) {
   return Attribute::getAttrKindFromName(StringRef(Name, SLen));
 }
@@ -4338,11 +4325,6 @@ LLVMValueRef LLVMBuildAtomicRMWSyncScope(LLVMBuilderRef B,
                                          LLVMAtomicOrdering ordering,
                                          unsigned SSID) {
   AtomicRMWInst::BinOp intop = mapFromLLVMRMWBinOp(op);
-
-  SmallVector<StringRef> SSNs;
-  unwrap(B)->getContext().getSyncScopeNames(SSNs);
-  assert(SSID < SSNs.size() && "Invalid SyncScopeID");
-
   return wrap(unwrap(B)->CreateAtomicRMW(intop, unwrap(PTR), unwrap(Val),
                                          MaybeAlign(),
                                          mapFromLLVMOrdering(ordering), SSID));
@@ -4386,49 +4368,22 @@ int LLVMGetMaskValue(LLVMValueRef SVInst, unsigned Elt) {
 
 int LLVMGetUndefMaskElem(void) { return PoisonMaskElem; }
 
-static unsigned getAtomicSyncScopeID(Value *P) {
-  if (AtomicRMWInst *I = dyn_cast<AtomicRMWInst>(P))
-    return I->getSyncScopeID();
-  else if (FenceInst *FI = dyn_cast<FenceInst>(P))
-    return FI->getSyncScopeID();
-  else if (StoreInst *SI = dyn_cast<StoreInst>(P))
-    return SI->getSyncScopeID();
-  else if (LoadInst *LI = dyn_cast<LoadInst>(P))
-    return LI->getSyncScopeID();
-  return cast<AtomicCmpXchgInst>(P)->getSyncScopeID();
-}
-
 LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) {
-  Value *P = unwrap(AtomicInst);
-  return getAtomicSyncScopeID(P) == SyncScope::SingleThread;
+  return getAtomicSyncScopeID(unwrap<Instruction>(AtomicInst)).value() ==
+         SyncScope::SingleThread;
 }
 
 unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) {
-  Value *P = unwrap(AtomicInst);
-  return getAtomicSyncScopeID(P);
-}
-
-static void setAtomicSyncScopeID(Value *P, unsigned SSID) {
-  if (AtomicRMWInst *I = dyn_cast<AtomicRMWInst>(P))
-    return I->setSyncScopeID(SSID);
-  else if (FenceInst *FI = dyn_cast<FenceInst>(P))
-    return FI->setSyncScopeID(SSID);
-  else if (StoreInst *SI = dyn_cast<StoreInst>(P))
-    return SI->setSyncScopeID(SSID);
-  else if (LoadInst *LI = dyn_cast<LoadInst>(P))
-    return LI->setSyncScopeID(SSID);
-  return cast<AtomicCmpXchgInst>(P)->setSyncScopeID(SSID);
+  return getAtomicSyncScopeID(unwrap<Instruction>(AtomicInst)).value();
 }
 
 void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) {
-  Value *P = unwrap(AtomicInst);
   SyncScope::ID SSID = NewValue ? SyncScope::SingleThread : SyncScope::System;
-  setAtomicSyncScopeID(P, SSID);
+  setAtomicSyncScopeID(unwrap<Instruction>(AtomicInst), SSID);
 }
 
 void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID) {
-  Value *P = unwrap(AtomicInst);
-  setAtomicSyncScopeID(P, SSID);
+  setAtomicSyncScopeID(unwrap<Instruction>(AtomicInst), SSID);
 }
 
 LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst)  {

>From ce5db1ec82a78e57caab172068dcf5e7ae5f486f Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Mon, 19 Aug 2024 20:45:39 +0200
Subject: [PATCH 4/4] Make LLVMIsAtomicSingleThread work on non-atomic
 instructions.

Add LLVMIsAtomic so that users can guard uses of LLVMGetAtomicSyncScopeID.
---
 llvm/include/llvm-c/Core.h      |  8 +++++++-
 llvm/lib/IR/Core.cpp            | 23 +++++++++++++++++------
 llvm/tools/llvm-c-test/echo.cpp | 24 ++++++++++++++----------
 3 files changed, 38 insertions(+), 17 deletions(-)

diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index c7a75ceb244a69..f375145d9d1d09 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -4630,7 +4630,13 @@ LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst);
 void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool SingleThread);
 
 /**
- * Returns the synchronization scope ID of an atomic instruction
+ * Returns whether an instruction is an atomic instruction, e.g., atomicrmw,
+ * cmpxchg, fence, or loads and stores with atomic ordering.
+ */
+LLVMBool LLVMIsAtomic(LLVMValueRef Inst);
+
+/**
+ * Returns the synchronization scope ID of an atomic instruction.
  */
 unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst);
 
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 18cc0354947384..5b4756ee64e476 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -4368,13 +4368,16 @@ int LLVMGetMaskValue(LLVMValueRef SVInst, unsigned Elt) {
 
 int LLVMGetUndefMaskElem(void) { return PoisonMaskElem; }
 
-LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) {
-  return getAtomicSyncScopeID(unwrap<Instruction>(AtomicInst)).value() ==
-         SyncScope::SingleThread;
+LLVMBool LLVMIsAtomic(LLVMValueRef Inst) {
+  return unwrap<Instruction>(Inst)->isAtomic();
 }
 
-unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) {
-  return getAtomicSyncScopeID(unwrap<Instruction>(AtomicInst)).value();
+LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) {
+  // Backwards compatibility: return false for non-atomic instructions
+  Instruction *I = unwrap<Instruction>(AtomicInst);
+  if (!I->isAtomic())
+    return 0;
+  return getAtomicSyncScopeID(I).value() == SyncScope::SingleThread;
 }
 
 void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) {
@@ -4382,8 +4385,16 @@ void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) {
   setAtomicSyncScopeID(unwrap<Instruction>(AtomicInst), SSID);
 }
 
+unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) {
+  Instruction *I = unwrap<Instruction>(AtomicInst);
+  assert(I->isAtomic() && "Expected an atomic instruction");
+  return getAtomicSyncScopeID(I).value();
+}
+
 void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID) {
-  setAtomicSyncScopeID(unwrap<Instruction>(AtomicInst), SSID);
+  Instruction *I = unwrap<Instruction>(AtomicInst);
+  assert(I->isAtomic() && "Expected an atomic instruction");
+  setAtomicSyncScopeID(I, SSID);
 }
 
 LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst)  {
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 696c6d6aa2fe0d..3ad1b58c50a882 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -755,11 +755,13 @@ struct FunCloner {
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetOrdering(Dst, LLVMGetOrdering(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
-        LLVMBool IsAtomicSingleThread = LLVMIsAtomicSingleThread(Src);
-        if (IsAtomicSingleThread)
-          LLVMSetAtomicSingleThread(Dst, IsAtomicSingleThread);
-        else
-          LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src));
+        if (LLVMIsAtomic(Src)) {
+          LLVMBool IsAtomicSingleThread = LLVMIsAtomicSingleThread(Src);
+          if (IsAtomicSingleThread)
+            LLVMSetAtomicSingleThread(Dst, IsAtomicSingleThread);
+          else
+            LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src));
+        }
         break;
       }
       case LLVMStore: {
@@ -769,11 +771,13 @@ struct FunCloner {
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetOrdering(Dst, LLVMGetOrdering(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
-        LLVMBool IsAtomicSingleThread = LLVMIsAtomicSingleThread(Src);
-        if (IsAtomicSingleThread)
-          LLVMSetAtomicSingleThread(Dst, IsAtomicSingleThread);
-        else
-          LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src));
+        if (LLVMIsAtomic(Src)) {
+          LLVMBool IsAtomicSingleThread = LLVMIsAtomicSingleThread(Src);
+          if (IsAtomicSingleThread)
+            LLVMSetAtomicSingleThread(Dst, IsAtomicSingleThread);
+          else
+            LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src));
+        }
         break;
       }
       case LLVMGetElementPtr: {



More information about the llvm-commits mailing list