From a86400d00a236670634fd171d80a0c5a41f39c8c Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 19 Aug 2024 14:45:08 +0200 Subject: [PATCH 1/6] [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 d40bb2682f9ad..3ab9e10970446 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 7d2e7c9552076..6c8b497c15dd7 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 dcad76ee8491d..c8362a236d8e6 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 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 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(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(P)) - return I->getSyncScopeID() == SyncScope::SingleThread; + return I->getSyncScopeID(); else if (FenceInst *FI = dyn_cast(P)) - return FI->getSyncScopeID() == SyncScope::SingleThread; + return FI->getSyncScopeID(); else if (StoreInst *SI = dyn_cast(P)) - return SI->getSyncScopeID() == SyncScope::SingleThread; + return SI->getSyncScopeID(); else if (LoadInst *LI = dyn_cast(P)) - return LI->getSyncScopeID() == SyncScope::SingleThread; - return cast(P)->getSyncScopeID() == - SyncScope::SingleThread; + return LI->getSyncScopeID(); + return cast(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(P)) return I->setSyncScopeID(SSID); else if (FenceInst *FI = dyn_cast(P)) @@ -4366,6 +4420,17 @@ void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) { return cast(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(P)->getSuccessOrdering()); diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll index 45e3d0357ebdf..c4b932034b501 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 Date: Mon, 19 Aug 2024 14:45:51 +0200 Subject: [PATCH 2/6] 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 487769f94dbcb..088684cd3ed36 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 1e78637bf47ca..696c6d6aa2fe0 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 00566660257e0..1da6596cd5a8f 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 9fc86cfe5404b..9698f0983d5b6 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 Date: Mon, 19 Aug 2024 16:43:02 +0200 Subject: [PATCH 3/6] 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 3ab9e10970446..145b30b1668ea 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 6c8b497c15dd7..c7a75ceb244a6 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 968737a843e29..5640a80c22d49 100644 --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -4942,6 +4942,25 @@ inline std::optional 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(I)) + AI->setSyncScopeID(SSID); + else if (auto *AI = dyn_cast(I)) + AI->setSyncScopeID(SSID); + else if (auto *AI = dyn_cast(I)) + AI->setSyncScopeID(SSID); + else if (auto *AI = dyn_cast(I)) + AI->setSyncScopeID(SSID); + else if (auto *AI = dyn_cast(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 c8362a236d8e6..18cc035494738 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 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 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(P)) - return I->getSyncScopeID(); - else if (FenceInst *FI = dyn_cast(P)) - return FI->getSyncScopeID(); - else if (StoreInst *SI = dyn_cast(P)) - return SI->getSyncScopeID(); - else if (LoadInst *LI = dyn_cast(P)) - return LI->getSyncScopeID(); - return cast(P)->getSyncScopeID(); -} - LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) { - Value *P = unwrap(AtomicInst); - return getAtomicSyncScopeID(P) == SyncScope::SingleThread; + return getAtomicSyncScopeID(unwrap(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(P)) - return I->setSyncScopeID(SSID); - else if (FenceInst *FI = dyn_cast(P)) - return FI->setSyncScopeID(SSID); - else if (StoreInst *SI = dyn_cast(P)) - return SI->setSyncScopeID(SSID); - else if (LoadInst *LI = dyn_cast(P)) - return LI->setSyncScopeID(SSID); - return cast(P)->setSyncScopeID(SSID); + return getAtomicSyncScopeID(unwrap(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(AtomicInst), SSID); } void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID) { - Value *P = unwrap(AtomicInst); - setAtomicSyncScopeID(P, SSID); + setAtomicSyncScopeID(unwrap(AtomicInst), SSID); } LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst) { From ce5db1ec82a78e57caab172068dcf5e7ae5f486f Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 19 Aug 2024 20:45:39 +0200 Subject: [PATCH 4/6] 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 c7a75ceb244a6..f375145d9d1d0 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 18cc035494738..5b4756ee64e47 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(AtomicInst)).value() == - SyncScope::SingleThread; +LLVMBool LLVMIsAtomic(LLVMValueRef Inst) { + return unwrap(Inst)->isAtomic(); } -unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) { - return getAtomicSyncScopeID(unwrap(AtomicInst)).value(); +LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) { + // Backwards compatibility: return false for non-atomic instructions + Instruction *I = unwrap(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(AtomicInst), SSID); } +unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) { + Instruction *I = unwrap(AtomicInst); + assert(I->isAtomic() && "Expected an atomic instruction"); + return getAtomicSyncScopeID(I).value(); +} + void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID) { - setAtomicSyncScopeID(unwrap(AtomicInst), SSID); + Instruction *I = unwrap(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 696c6d6aa2fe0..3ad1b58c50a88 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: { From b4ad3c6a5e1f5e7a9f1e6b25f56d6540d51a2e72 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 20 Aug 2024 11:55:21 +0200 Subject: [PATCH 5/6] Address review comments. --- llvm/docs/ReleaseNotes.rst | 6 ++- llvm/lib/IR/Core.cpp | 4 +- llvm/tools/llvm-c-test/CMakeLists.txt | 1 + llvm/tools/llvm-c-test/atomic.c | 64 +++++++++++++++++++++++++++ llvm/tools/llvm-c-test/echo.cpp | 44 +++++------------- llvm/tools/llvm-c-test/llvm-c-test.h | 3 ++ llvm/tools/llvm-c-test/main.c | 2 + 7 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 llvm/tools/llvm-c-test/atomic.c diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index 145b30b1668ea..8e6309eeb6342 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -165,12 +165,16 @@ Changes to the C API * Support for creating instructions with custom synchronization scopes has been added: - * ``LLVMGetSyncScopeID`` to map a synchronization scope name to an ID + * ``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/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index 5b4756ee64e47..ed6f9c0aae95a 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -4377,7 +4377,7 @@ LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) { Instruction *I = unwrap(AtomicInst); if (!I->isAtomic()) return 0; - return getAtomicSyncScopeID(I).value() == SyncScope::SingleThread; + return *getAtomicSyncScopeID(I) == SyncScope::SingleThread; } void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) { @@ -4388,7 +4388,7 @@ void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) { unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) { Instruction *I = unwrap(AtomicInst); assert(I->isAtomic() && "Expected an atomic instruction"); - return getAtomicSyncScopeID(I).value(); + return *getAtomicSyncScopeID(I); } void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID) { diff --git a/llvm/tools/llvm-c-test/CMakeLists.txt b/llvm/tools/llvm-c-test/CMakeLists.txt index 939164e636216..8382c4b1bfad5 100644 --- a/llvm/tools/llvm-c-test/CMakeLists.txt +++ b/llvm/tools/llvm-c-test/CMakeLists.txt @@ -41,6 +41,7 @@ endif () add_llvm_tool(llvm-c-test attributes.c + atomic.c calc.c debuginfo.c diagnostic.c diff --git a/llvm/tools/llvm-c-test/atomic.c b/llvm/tools/llvm-c-test/atomic.c new file mode 100644 index 0000000000000..6befa5ce9efd5 --- /dev/null +++ b/llvm/tools/llvm-c-test/atomic.c @@ -0,0 +1,64 @@ +/*===-- atomic.c - tool for testing libLLVM and llvm-c API ----------------===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file implements the --atomic-* commands in llvm-c-test. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include +#include +#include +#include + +int llvm_atomic_syncscope(void) { + LLVMBuilderRef Builder = LLVMCreateBuilder(); + + LLVMModuleRef M = LLVMModuleCreateWithName("Mod"); + LLVMTypeRef FT = LLVMFunctionType(LLVMVoidType(), NULL, 0, 0); + LLVMValueRef F = LLVMAddFunction(M, "Fun", FT); + LLVMBasicBlockRef BB = LLVMAppendBasicBlock(F, "Entry"); + LLVMPositionBuilderAtEnd(Builder, BB); + + // echo.cpp already tests the new SyncScope APIs, also test the old ones here + + // fence + LLVMValueRef Fence = + LLVMBuildFence(Builder, LLVMAtomicOrderingSequentiallyConsistent, 0, ""); + assert(!LLVMIsAtomicSingleThread(Fence)); + Fence = + LLVMBuildFence(Builder, LLVMAtomicOrderingSequentiallyConsistent, 1, ""); + assert(LLVMIsAtomicSingleThread(Fence)); + + // atomicrmw + LLVMValueRef Ptr = LLVMConstPointerNull(LLVMPointerType(LLVMInt32Type(), 0)); + LLVMValueRef Val = LLVMConstInt(LLVMInt32Type(), 0, 0); + LLVMValueRef AtomicRMW = + LLVMBuildAtomicRMW(Builder, LLVMAtomicRMWBinOpXchg, Ptr, Val, + LLVMAtomicOrderingSequentiallyConsistent, 0); + assert(!LLVMIsAtomicSingleThread(AtomicRMW)); + AtomicRMW = LLVMBuildAtomicRMW(Builder, LLVMAtomicRMWBinOpXchg, Ptr, Val, + LLVMAtomicOrderingSequentiallyConsistent, 1); + assert(LLVMIsAtomicSingleThread(AtomicRMW)); + + // cmpxchg + LLVMValueRef CmpXchg = LLVMBuildAtomicCmpXchg( + Builder, Ptr, Val, Val, LLVMAtomicOrderingSequentiallyConsistent, + LLVMAtomicOrderingSequentiallyConsistent, 0); + assert(!LLVMIsAtomicSingleThread(CmpXchg)); + CmpXchg = LLVMBuildAtomicCmpXchg(Builder, Ptr, Val, Val, + LLVMAtomicOrderingSequentiallyConsistent, + LLVMAtomicOrderingSequentiallyConsistent, 1); + assert(LLVMIsAtomicSingleThread(CmpXchg)); + + LLVMDisposeBuilder(Builder); + LLVMDisposeModule(M); + + return 0; +} diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp index 3ad1b58c50a88..4173e49e60a04 100644 --- a/llvm/tools/llvm-c-test/echo.cpp +++ b/llvm/tools/llvm-c-test/echo.cpp @@ -755,13 +755,8 @@ struct FunCloner { LLVMSetAlignment(Dst, LLVMGetAlignment(Src)); LLVMSetOrdering(Dst, LLVMGetOrdering(Src)); LLVMSetVolatile(Dst, LLVMGetVolatile(Src)); - if (LLVMIsAtomic(Src)) { - LLVMBool IsAtomicSingleThread = LLVMIsAtomicSingleThread(Src); - if (IsAtomicSingleThread) - LLVMSetAtomicSingleThread(Dst, IsAtomicSingleThread); - else - LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src)); - } + if (LLVMIsAtomic(Src)) + LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src)); break; } case LLVMStore: { @@ -771,13 +766,8 @@ struct FunCloner { LLVMSetAlignment(Dst, LLVMGetAlignment(Src)); LLVMSetOrdering(Dst, LLVMGetOrdering(Src)); LLVMSetVolatile(Dst, LLVMGetVolatile(Src)); - if (LLVMIsAtomic(Src)) { - LLVMBool IsAtomicSingleThread = LLVMIsAtomicSingleThread(Src); - if (IsAtomicSingleThread) - LLVMSetAtomicSingleThread(Dst, IsAtomicSingleThread); - else - LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src)); - } + if (LLVMIsAtomic(Src)) + LLVMSetAtomicSyncScopeID(Dst, LLVMGetAtomicSyncScopeID(Src)); break; } case LLVMGetElementPtr: { @@ -798,12 +788,8 @@ struct FunCloner { LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 1)); LLVMAtomicRMWBinOp BinOp = LLVMGetAtomicRMWBinOp(Src); LLVMAtomicOrdering Ord = LLVMGetOrdering(Src); - LLVMBool SingleThread = LLVMIsAtomicSingleThread(Src); - if (SingleThread) - Dst = LLVMBuildAtomicRMW(Builder, BinOp, Ptr, Val, Ord, SingleThread); - else - Dst = LLVMBuildAtomicRMWSyncScope(Builder, BinOp, Ptr, Val, Ord, - LLVMGetAtomicSyncScopeID(Src)); + Dst = LLVMBuildAtomicRMWSyncScope(Builder, BinOp, Ptr, Val, Ord, + LLVMGetAtomicSyncScopeID(Src)); LLVMSetAlignment(Dst, LLVMGetAlignment(Src)); LLVMSetVolatile(Dst, LLVMGetVolatile(Src)); LLVMSetValueName2(Dst, Name, NameLen); @@ -815,14 +801,8 @@ struct FunCloner { LLVMValueRef New = CloneValue(LLVMGetOperand(Src, 2)); LLVMAtomicOrdering Succ = LLVMGetCmpXchgSuccessOrdering(Src); LLVMAtomicOrdering Fail = LLVMGetCmpXchgFailureOrdering(Src); - LLVMBool SingleThread = LLVMIsAtomicSingleThread(Src); - if (SingleThread) - Dst = LLVMBuildAtomicCmpXchg(Builder, Ptr, Cmp, New, Succ, Fail, - SingleThread); - else - Dst = LLVMBuildAtomicCmpXchgSyncScope(Builder, Ptr, Cmp, New, Succ, - Fail, - LLVMGetAtomicSyncScopeID(Src)); + Dst = LLVMBuildAtomicCmpXchgSyncScope( + Builder, Ptr, Cmp, New, Succ, Fail, LLVMGetAtomicSyncScopeID(Src)); LLVMSetAlignment(Dst, LLVMGetAlignment(Src)); LLVMSetVolatile(Dst, LLVMGetVolatile(Src)); LLVMSetWeak(Dst, LLVMGetWeak(Src)); @@ -1013,12 +993,8 @@ struct FunCloner { } case LLVMFence: { LLVMAtomicOrdering Ordering = LLVMGetOrdering(Src); - LLVMBool IsSingleThreaded = LLVMIsAtomicSingleThread(Src); - if (IsSingleThreaded) - Dst = LLVMBuildFence(Builder, Ordering, IsSingleThreaded, Name); - else - Dst = LLVMBuildFenceSyncScope(Builder, Ordering, - LLVMGetAtomicSyncScopeID(Src), Name); + Dst = LLVMBuildFenceSyncScope(Builder, Ordering, + LLVMGetAtomicSyncScopeID(Src), Name); break; } case LLVMZExt: { diff --git a/llvm/tools/llvm-c-test/llvm-c-test.h b/llvm/tools/llvm-c-test/llvm-c-test.h index 1da6596cd5a8f..74c4fadc3bd94 100644 --- a/llvm/tools/llvm-c-test/llvm-c-test.h +++ b/llvm/tools/llvm-c-test/llvm-c-test.h @@ -63,6 +63,9 @@ int llvm_test_diagnostic_handler(void); int llvm_test_function_attributes(void); int llvm_test_callsite_attributes(void); +// atomic.c +int llvm_atomic_syncscope(void); + #ifdef __cplusplus } #endif /* !defined(__cplusplus) */ diff --git a/llvm/tools/llvm-c-test/main.c b/llvm/tools/llvm-c-test/main.c index 8be9ea06fc68d..c0311a35db07d 100644 --- a/llvm/tools/llvm-c-test/main.c +++ b/llvm/tools/llvm-c-test/main.c @@ -112,6 +112,8 @@ int main(int argc, char **argv) { } else if (argc == 2 && !strcmp(argv[1], "--test-dibuilder-debuginfo-format")) { return llvm_test_dibuilder(); + } else if (argc == 2 && !strcmp(argv[1], "--atomic-syncscope")) { + return llvm_atomic_syncscope(); } else { print_usage(); } From 41aa2040fa263f38d77795b1607135e0932b69fa Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 20 Aug 2024 13:00:40 +0200 Subject: [PATCH 6/6] Address more review comments. --- llvm/include/llvm/IR/Instructions.h | 4 +- llvm/lib/IR/Core.cpp | 8 +++- llvm/tools/llvm-c-test/CMakeLists.txt | 1 - llvm/tools/llvm-c-test/atomic.c | 64 -------------------------- llvm/tools/llvm-c-test/llvm-c-test.h | 3 -- llvm/tools/llvm-c-test/main.c | 2 - llvm/unittests/IR/InstructionsTest.cpp | 52 +++++++++++++++++++-- 7 files changed, 57 insertions(+), 77 deletions(-) delete mode 100644 llvm/tools/llvm-c-test/atomic.c diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h index 5640a80c22d49..dbd7d49a3e767 100644 --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -4943,10 +4943,8 @@ inline std::optional getAtomicSyncScopeID(const Instruction *I) { } /// 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; + assert(I->isAtomic()); if (auto *AI = dyn_cast(I)) AI->setSyncScopeID(SSID); else if (auto *AI = dyn_cast(I)) diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index ed6f9c0aae95a..9246f1101f378 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -4377,12 +4377,18 @@ LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) { Instruction *I = unwrap(AtomicInst); if (!I->isAtomic()) return 0; + return *getAtomicSyncScopeID(I) == SyncScope::SingleThread; } void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool NewValue) { + // Backwards compatibility: ignore non-atomic instructions + Instruction *I = unwrap(AtomicInst); + if (!I->isAtomic()) + return; + SyncScope::ID SSID = NewValue ? SyncScope::SingleThread : SyncScope::System; - setAtomicSyncScopeID(unwrap(AtomicInst), SSID); + setAtomicSyncScopeID(I, SSID); } unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) { diff --git a/llvm/tools/llvm-c-test/CMakeLists.txt b/llvm/tools/llvm-c-test/CMakeLists.txt index 8382c4b1bfad5..939164e636216 100644 --- a/llvm/tools/llvm-c-test/CMakeLists.txt +++ b/llvm/tools/llvm-c-test/CMakeLists.txt @@ -41,7 +41,6 @@ endif () add_llvm_tool(llvm-c-test attributes.c - atomic.c calc.c debuginfo.c diagnostic.c diff --git a/llvm/tools/llvm-c-test/atomic.c b/llvm/tools/llvm-c-test/atomic.c deleted file mode 100644 index 6befa5ce9efd5..0000000000000 --- a/llvm/tools/llvm-c-test/atomic.c +++ /dev/null @@ -1,64 +0,0 @@ -/*===-- atomic.c - tool for testing libLLVM and llvm-c API ----------------===*\ -|* *| -|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| -|* Exceptions. *| -|* See https://llvm.org/LICENSE.txt for license information. *| -|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| -|* *| -|*===----------------------------------------------------------------------===*| -|* *| -|* This file implements the --atomic-* commands in llvm-c-test. *| -|* *| -\*===----------------------------------------------------------------------===*/ - -#include "llvm-c-test.h" -#include -#include -#include -#include - -int llvm_atomic_syncscope(void) { - LLVMBuilderRef Builder = LLVMCreateBuilder(); - - LLVMModuleRef M = LLVMModuleCreateWithName("Mod"); - LLVMTypeRef FT = LLVMFunctionType(LLVMVoidType(), NULL, 0, 0); - LLVMValueRef F = LLVMAddFunction(M, "Fun", FT); - LLVMBasicBlockRef BB = LLVMAppendBasicBlock(F, "Entry"); - LLVMPositionBuilderAtEnd(Builder, BB); - - // echo.cpp already tests the new SyncScope APIs, also test the old ones here - - // fence - LLVMValueRef Fence = - LLVMBuildFence(Builder, LLVMAtomicOrderingSequentiallyConsistent, 0, ""); - assert(!LLVMIsAtomicSingleThread(Fence)); - Fence = - LLVMBuildFence(Builder, LLVMAtomicOrderingSequentiallyConsistent, 1, ""); - assert(LLVMIsAtomicSingleThread(Fence)); - - // atomicrmw - LLVMValueRef Ptr = LLVMConstPointerNull(LLVMPointerType(LLVMInt32Type(), 0)); - LLVMValueRef Val = LLVMConstInt(LLVMInt32Type(), 0, 0); - LLVMValueRef AtomicRMW = - LLVMBuildAtomicRMW(Builder, LLVMAtomicRMWBinOpXchg, Ptr, Val, - LLVMAtomicOrderingSequentiallyConsistent, 0); - assert(!LLVMIsAtomicSingleThread(AtomicRMW)); - AtomicRMW = LLVMBuildAtomicRMW(Builder, LLVMAtomicRMWBinOpXchg, Ptr, Val, - LLVMAtomicOrderingSequentiallyConsistent, 1); - assert(LLVMIsAtomicSingleThread(AtomicRMW)); - - // cmpxchg - LLVMValueRef CmpXchg = LLVMBuildAtomicCmpXchg( - Builder, Ptr, Val, Val, LLVMAtomicOrderingSequentiallyConsistent, - LLVMAtomicOrderingSequentiallyConsistent, 0); - assert(!LLVMIsAtomicSingleThread(CmpXchg)); - CmpXchg = LLVMBuildAtomicCmpXchg(Builder, Ptr, Val, Val, - LLVMAtomicOrderingSequentiallyConsistent, - LLVMAtomicOrderingSequentiallyConsistent, 1); - assert(LLVMIsAtomicSingleThread(CmpXchg)); - - LLVMDisposeBuilder(Builder); - LLVMDisposeModule(M); - - return 0; -} diff --git a/llvm/tools/llvm-c-test/llvm-c-test.h b/llvm/tools/llvm-c-test/llvm-c-test.h index 74c4fadc3bd94..1da6596cd5a8f 100644 --- a/llvm/tools/llvm-c-test/llvm-c-test.h +++ b/llvm/tools/llvm-c-test/llvm-c-test.h @@ -63,9 +63,6 @@ int llvm_test_diagnostic_handler(void); int llvm_test_function_attributes(void); int llvm_test_callsite_attributes(void); -// atomic.c -int llvm_atomic_syncscope(void); - #ifdef __cplusplus } #endif /* !defined(__cplusplus) */ diff --git a/llvm/tools/llvm-c-test/main.c b/llvm/tools/llvm-c-test/main.c index c0311a35db07d..8be9ea06fc68d 100644 --- a/llvm/tools/llvm-c-test/main.c +++ b/llvm/tools/llvm-c-test/main.c @@ -112,8 +112,6 @@ int main(int argc, char **argv) { } else if (argc == 2 && !strcmp(argv[1], "--test-dibuilder-debuginfo-format")) { return llvm_test_dibuilder(); - } else if (argc == 2 && !strcmp(argv[1], "--atomic-syncscope")) { - return llvm_atomic_syncscope(); } else { print_usage(); } diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp index 44b25035dde2c..529edc88ebc33 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