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

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 20 05:12:38 PDT 2024


Author: Tim Besard
Date: 2024-08-20T14:12:35+02:00
New Revision: eb7d535199d7fc3de763276093b97141a041d3d6

URL: https://github.com/llvm/llvm-project/commit/eb7d535199d7fc3de763276093b97141a041d3d6
DIFF: https://github.com/llvm/llvm-project/commit/eb7d535199d7fc3de763276093b97141a041d3d6.diff

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

Another upstreaming of C API extensions we have in Julia/LLVM.jl.
Although [we went](https://github.com/maleadt/LLVM.jl/pull/431) with a
string-based API there, here I'm proposing something that's similar to
existing metadata/attribute APIs:
- explicit functions to map syncscope names to IDs, and back
- `LLVM*SyncScope` versions of builder APIs that already take a
`SingleThread` argument: atomic rmw, atomic xchg, fence
- `LLVMGetAtomicSyncScopeID` and `LLVMSetAtomicSyncScopeID` for other
atomic instructions
- testing through `llvm-c-test`'s `--echo` functionality

Added: 
    

Modified: 
    llvm/docs/ReleaseNotes.rst
    llvm/include/llvm-c/Core.h
    llvm/include/llvm/IR/Instructions.h
    llvm/lib/IR/Core.cpp
    llvm/test/Bindings/llvm-c/echo.ll
    llvm/tools/llvm-c-test/attributes.c
    llvm/tools/llvm-c-test/echo.cpp
    llvm/tools/llvm-c-test/llvm-c-test.h
    llvm/tools/llvm-c-test/module.c
    llvm/unittests/IR/InstructionsTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 7405023f9f27ed..005c59e00fb128 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -169,6 +169,19 @@ 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`` 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.
+  * ``LLVMGetAtomicSyncScopeID`` and ``LLVMSetAtomicSyncScopeID`` to get and set the
+    synchronization scope of any atomic instruction.
+  * ``LLVMIsAtomic`` to check if an instruction is atomic, for use with the above functions.
+    Because of backwards compatibility, ``LLVMIsAtomicSingleThread`` and
+    ``LLVMSetAtomicSingleThread`` continue to work with any instruction type.
+
+
 Changes to the CodeGen infrastructure
 -------------------------------------
 

diff  --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 6c45af41631e7e..a0786efb51fdb2 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -646,6 +646,11 @@ 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 LLVMGetSyncScopeID(LLVMContextRef C, const char *Name, size_t SLen);
+
 /**
  * Return an unique id given the name of a enum attribute,
  * or 0 if no attribute by that name exists.
@@ -4592,15 +4597,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.
@@ -4625,6 +4643,22 @@ int LLVMGetMaskValue(LLVMValueRef ShuffleVectorInst, unsigned Elt);
 LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst);
 void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool SingleThread);
 
+/**
+ * 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);
+
+/**
+ * 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/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 968737a843e292..dbd7d49a3e7672 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -4942,6 +4942,23 @@ 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.
+inline void setAtomicSyncScopeID(Instruction *I, SyncScope::ID SSID) {
+  assert(I->isAtomic());
+  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 fc5c6222fc7880..7665385025bd91 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,6 +147,10 @@ unsigned LLVMGetMDKindID(const char *Name, unsigned SLen) {
   return LLVMGetMDKindIDInContext(LLVMGetGlobalContext(), Name, SLen);
 }
 
+unsigned LLVMGetSyncScopeID(LLVMContextRef C, const char *Name, size_t SLen) {
+  return unwrap(C)->getOrInsertSyncScopeID(StringRef(Name, SLen));
+}
+
 unsigned LLVMGetEnumAttributeKindForName(const char *Name, size_t SLen) {
   return Attribute::getAttrKindFromName(StringRef(Name, SLen));
 }
@@ -3957,8 +3962,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(
@@ -3968,6 +3971,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) {
@@ -4317,6 +4327,17 @@ 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);
+  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,
@@ -4330,6 +4351,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);
@@ -4344,34 +4376,39 @@ int LLVMGetMaskValue(LLVMValueRef SVInst, unsigned Elt) {
 
 int LLVMGetUndefMaskElem(void) { return PoisonMaskElem; }
 
+LLVMBool LLVMIsAtomic(LLVMValueRef Inst) {
+  return unwrap<Instruction>(Inst)->isAtomic();
+}
+
 LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) {
-  Value *P = unwrap(AtomicInst);
+  // Backwards compatibility: return false for non-atomic instructions
+  Instruction *I = unwrap<Instruction>(AtomicInst);
+  if (!I->isAtomic())
+    return 0;
 
-  if (AtomicRMWInst *I = dyn_cast<AtomicRMWInst>(P))
-    return I->getSyncScopeID() == SyncScope::SingleThread;
-  else if (FenceInst *FI = dyn_cast<FenceInst>(P))
-    return FI->getSyncScopeID() == SyncScope::SingleThread;
-  else if (StoreInst *SI = dyn_cast<StoreInst>(P))
-    return SI->getSyncScopeID() == SyncScope::SingleThread;
-  else if (LoadInst *LI = dyn_cast<LoadInst>(P))
-    return LI->getSyncScopeID() == SyncScope::SingleThread;
-  return cast<AtomicCmpXchgInst>(P)->getSyncScopeID() ==
-             SyncScope::SingleThread;
+  return *getAtomicSyncScopeID(I) == SyncScope::SingleThread;
 }
 
 void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) {
-  Value *P = unwrap(AtomicInst);
+  // Backwards compatibility: ignore non-atomic instructions
+  Instruction *I = unwrap<Instruction>(AtomicInst);
+  if (!I->isAtomic())
+    return;
+
   SyncScope::ID SSID = NewValue ? SyncScope::SingleThread : SyncScope::System;
+  setAtomicSyncScopeID(I, 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);
+unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) {
+  Instruction *I = unwrap<Instruction>(AtomicInst);
+  assert(I->isAtomic() && "Expected an atomic instruction");
+  return *getAtomicSyncScopeID(I);
+}
+
+void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID) {
+  Instruction *I = unwrap<Instruction>(AtomicInst);
+  assert(I->isAtomic() && "Expected an atomic instruction");
+  setAtomicSyncScopeID(I, SSID);
 }
 
 LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst)  {

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
 }
 

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..4173e49e60a046 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,8 @@ struct FunCloner {
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetOrdering(Dst, LLVMGetOrdering(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
-        LLVMSetAtomicSingleThread(Dst, LLVMIsAtomicSingleThread(Src));
+        if (LLVMIsAtomic(Src))
+          LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src));
         break;
       }
       case LLVMStore: {
@@ -764,7 +766,8 @@ struct FunCloner {
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetOrdering(Dst, LLVMGetOrdering(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
-        LLVMSetAtomicSingleThread(Dst, LLVMIsAtomicSingleThread(Src));
+        if (LLVMIsAtomic(Src))
+          LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src));
         break;
       }
       case LLVMGetElementPtr: {
@@ -785,8 +788,8 @@ struct FunCloner {
         LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 1));
         LLVMAtomicRMWBinOp BinOp = LLVMGetAtomicRMWBinOp(Src);
         LLVMAtomicOrdering Ord = LLVMGetOrdering(Src);
-        LLVMBool SingleThread = LLVMIsAtomicSingleThread(Src);
-        Dst = LLVMBuildAtomicRMW(Builder, BinOp, Ptr, Val, Ord, SingleThread);
+        Dst = LLVMBuildAtomicRMWSyncScope(Builder, BinOp, Ptr, Val, Ord,
+                                          LLVMGetAtomicSyncScopeID(Src));
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
         LLVMSetValueName2(Dst, Name, NameLen);
@@ -798,10 +801,8 @@ struct FunCloner {
         LLVMValueRef New = CloneValue(LLVMGetOperand(Src, 2));
         LLVMAtomicOrdering Succ = LLVMGetCmpXchgSuccessOrdering(Src);
         LLVMAtomicOrdering Fail = LLVMGetCmpXchgFailureOrdering(Src);
-        LLVMBool SingleThread = LLVMIsAtomicSingleThread(Src);
-
-        Dst = LLVMBuildAtomicCmpXchg(Builder, Ptr, Cmp, New, Succ, Fail,
-                                     SingleThread);
+        Dst = LLVMBuildAtomicCmpXchgSyncScope(
+            Builder, Ptr, Cmp, New, Succ, Fail, LLVMGetAtomicSyncScopeID(Src));
         LLVMSetAlignment(Dst, LLVMGetAlignment(Src));
         LLVMSetVolatile(Dst, LLVMGetVolatile(Src));
         LLVMSetWeak(Dst, LLVMGetWeak(Src));
@@ -992,8 +993,8 @@ struct FunCloner {
       }
       case LLVMFence: {
         LLVMAtomicOrdering Ordering = LLVMGetOrdering(Src);
-        LLVMBool IsSingleThreaded = LLVMIsAtomicSingleThread(Src);
-        Dst = LLVMBuildFence(Builder, Ordering, IsSingleThreaded, Name);
+        Dst = LLVMBuildFenceSyncScope(Builder, Ordering,
+                                      LLVMGetAtomicSyncScopeID(Src), Name);
         break;
       }
       case LLVMZExt: {
@@ -1059,7 +1060,6 @@ struct FunCloner {
     if (LLVMCanValueUseFastMathFlags(Src))
       LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
 
-    auto Ctx = LLVMGetModuleContext(M);
     size_t NumMetadataEntries;
     auto *AllMetadata =
         LLVMInstructionGetAllMetadataOtherThanDebugLoc(Src,
@@ -1609,12 +1609,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);

diff  --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp
index 44b25035dde2c5..529edc88ebc331 100644
--- a/llvm/unittests/IR/InstructionsTest.cpp
+++ b/llvm/unittests/IR/InstructionsTest.cpp
@@ -1159,7 +1159,8 @@ TEST(InstructionsTest, ShuffleMaskQueries) {
   EXPECT_TRUE(
       ShuffleVectorInst::isTransposeMask(ConstantVector::get({C1, C3}), 2));
 
-  // Nothing special about the values here - just re-using inputs to reduce code. 
+  // Nothing special about the values here - just re-using inputs to reduce
+  // code.
   Constant *V0 = ConstantVector::get({C0, C1, C2, C3});
   Constant *V1 = ConstantVector::get({C3, C2, C1, C0});
 
@@ -1216,7 +1217,7 @@ TEST(InstructionsTest, ShuffleMaskQueries) {
   EXPECT_FALSE(Id6->isIdentityWithExtract());
   EXPECT_FALSE(Id6->isConcat());
   delete Id6;
-  
+
   // Result has more elements than operands, but extra elements are not undef.
   ShuffleVectorInst *Id7 = new ShuffleVectorInst(V0, V1,
                                                  ConstantVector::get({C0, C1, C2, C3, CU, C1}));
@@ -1225,7 +1226,7 @@ TEST(InstructionsTest, ShuffleMaskQueries) {
   EXPECT_FALSE(Id7->isIdentityWithExtract());
   EXPECT_FALSE(Id7->isConcat());
   delete Id7;
-  
+
   // Result has more elements than operands; choose from Op0 and Op1 is not identity.
   ShuffleVectorInst *Id8 = new ShuffleVectorInst(V0, V1,
                                                  ConstantVector::get({C4, CU, C2, C3, CU, CU}));
@@ -1814,5 +1815,50 @@ TEST(InstructionsTest, InsertAtEnd) {
   EXPECT_EQ(Ret->getNextNode(), I);
 }
 
+TEST(InstructionsTest, AtomicSyncscope) {
+  LLVMContext Ctx;
+
+  Module M("Mod", Ctx);
+  FunctionType *FT = FunctionType::get(Type::getVoidTy(Ctx), {}, false);
+  Function *F = Function::Create(FT, Function::ExternalLinkage, "Fun", M);
+  BasicBlock *BB = BasicBlock::Create(Ctx, "Entry", F);
+  IRBuilder<> Builder(BB);
+
+  // SyncScope-variants of LLVM C IRBuilder APIs are tested by llvm-c-test,
+  // so cover the old versions (with a SingleThreaded argument) here.
+  Value *Ptr = ConstantPointerNull::get(Builder.getPtrTy());
+  Value *Val = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
+
+  // fence
+  LLVMValueRef Fence = LLVMBuildFence(
+      wrap(&Builder), LLVMAtomicOrderingSequentiallyConsistent, 0, "");
+  EXPECT_FALSE(LLVMIsAtomicSingleThread(Fence));
+  Fence = LLVMBuildFence(wrap(&Builder),
+                         LLVMAtomicOrderingSequentiallyConsistent, 1, "");
+  EXPECT_TRUE(LLVMIsAtomicSingleThread(Fence));
+
+  // atomicrmw
+  LLVMValueRef AtomicRMW = LLVMBuildAtomicRMW(
+      wrap(&Builder), LLVMAtomicRMWBinOpXchg, wrap(Ptr), wrap(Val),
+      LLVMAtomicOrderingSequentiallyConsistent, 0);
+  EXPECT_FALSE(LLVMIsAtomicSingleThread(AtomicRMW));
+  AtomicRMW = LLVMBuildAtomicRMW(wrap(&Builder), LLVMAtomicRMWBinOpXchg,
+                                 wrap(Ptr), wrap(Val),
+                                 LLVMAtomicOrderingSequentiallyConsistent, 1);
+  EXPECT_TRUE(LLVMIsAtomicSingleThread(AtomicRMW));
+
+  // cmpxchg
+  LLVMValueRef CmpXchg =
+      LLVMBuildAtomicCmpXchg(wrap(&Builder), wrap(Ptr), wrap(Val), wrap(Val),
+                             LLVMAtomicOrderingSequentiallyConsistent,
+                             LLVMAtomicOrderingSequentiallyConsistent, 0);
+  EXPECT_FALSE(LLVMIsAtomicSingleThread(CmpXchg));
+  CmpXchg =
+      LLVMBuildAtomicCmpXchg(wrap(&Builder), wrap(Ptr), wrap(Val), wrap(Val),
+                             LLVMAtomicOrderingSequentiallyConsistent,
+                             LLVMAtomicOrderingSequentiallyConsistent, 1);
+  EXPECT_TRUE(LLVMIsAtomicSingleThread(CmpXchg));
+}
+
 } // end anonymous namespace
 } // end namespace llvm


        


More information about the llvm-commits mailing list