diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index d40bb2682f9ad8..8e6309eeb6342c 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -163,6 +163,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 7d2e7c95520761..f375145d9d1d09 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. @@ -4578,15 +4583,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 +4629,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 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(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 dcad76ee8491dd..9246f1101f3783 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)); } @@ -3949,8 +3954,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 +3963,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 +4319,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, @@ -4322,6 +4343,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,34 +4368,39 @@ int LLVMGetMaskValue(LLVMValueRef SVInst, unsigned Elt) { int LLVMGetUndefMaskElem(void) { return PoisonMaskElem; } +LLVMBool LLVMIsAtomic(LLVMValueRef Inst) { + return unwrap(Inst)->isAtomic(); +} + LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) { - Value *P = unwrap(AtomicInst); + // Backwards compatibility: return false for non-atomic instructions + Instruction *I = unwrap(AtomicInst); + if (!I->isAtomic()) + return 0; - if (AtomicRMWInst *I = dyn_cast(P)) - return I->getSyncScopeID() == SyncScope::SingleThread; - else if (FenceInst *FI = dyn_cast(P)) - return FI->getSyncScopeID() == SyncScope::SingleThread; - else if (StoreInst *SI = dyn_cast(P)) - return SI->getSyncScopeID() == SyncScope::SingleThread; - else if (LoadInst *LI = dyn_cast(P)) - return LI->getSyncScopeID() == SyncScope::SingleThread; - return cast(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(AtomicInst); + if (!I->isAtomic()) + return; + SyncScope::ID SSID = NewValue ? SyncScope::SingleThread : SyncScope::System; + setAtomicSyncScopeID(I, 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); +unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst) { + Instruction *I = unwrap(AtomicInst); + assert(I->isAtomic() && "Expected an atomic instruction"); + return *getAtomicSyncScopeID(I); +} + +void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID) { + Instruction *I = unwrap(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