diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1608,21 +1608,17 @@ call is dead after inlining. ``nofree`` This function attribute indicates that the function does not, directly or - transitively, call a memory-deallocation function (``free``, for example) - on a memory allocation which existed before the call. + transitively, call a memory-deallocation function (``free``, for example), + or cause such a function to be called by another thread, on a memory + allocation which existed before the call. - As a result, uncaptured pointers that are known to be dereferenceable - prior to a call to a function with the ``nofree`` attribute are still - known to be dereferenceable after the call. The capturing condition is - necessary in environments where the function might communicate the - pointer to another thread which then deallocates the memory. Alternatively, - ``nosync`` would ensure such communication cannot happen and even captured - pointers cannot be freed by the function. + As a result, pointers that are known to be dereferenceable prior to a call + to a function with the ``nofree`` attribute are still known to be + dereferenceable after the call. A ``nofree`` function is explicitly allowed to free memory which it - allocated or (if not ``nosync``) arrange for another thread to free - memory on it's behalf. As a result, perhaps surprisingly, a ``nofree`` - function can return a pointer to a previously deallocated memory object. + allocated. As a result, perhaps surprisingly, a ``nofree`` function can + return a pointer to a previously deallocated memory object. ``noimplicitfloat`` This attributes disables implicit floating-point instructions. ``noinline`` diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -758,7 +758,7 @@ // allocations in existance before the call; a nofree function *is* allowed // to free memory it allocated. const Function *F = A->getParent(); - if (F->doesNotFreeMemory() && F->hasNoSync()) + if (F->doesNotFreeMemory()) return false; } diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -1277,16 +1277,11 @@ /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; - /// Helper function used to determine whether an instruction is non-relaxed - /// atomic. In other words, if an atomic instruction does not have unordered - /// or monotonic ordering - static bool isNonRelaxedAtomic(Instruction *I); - /// Helper function specific for intrinsics which are potentially volatile static bool isNoSyncIntrinsic(Instruction *I); }; -bool AANoSyncImpl::isNonRelaxedAtomic(Instruction *I) { +static bool isNonRelaxedAtomic(Instruction *I) { if (!I->isAtomic()) return false; @@ -1422,7 +1417,15 @@ return NoFreeAA.isAssumedNoFree(); }; - if (!A.checkForAllCallLikeInstructions(CheckForNoFree, *this)) + auto CheckForNoRemoteFree = [&](Instruction &I) { + if (I.isVolatile() || isNonRelaxedAtomic(&I)) + return false; + + return true; + }; + + if (!A.checkForAllCallLikeInstructions(CheckForNoFree, *this) || + !A.checkForAllReadWriteInstructions(CheckForNoRemoteFree, *this)) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; } diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1236,6 +1236,29 @@ } // end anonymous namespace +// Return true if this is an atomic which has an ordering stronger than +// unordered. Note that this is different than the predicate we use in +// Attributor. Here we chose to be conservative and consider monotonic +// operations potentially synchronizing. We generally don't do much with +// monotonic operations, so this is simply risk reduction. +static bool isOrderedAtomic(Instruction *I) { + if (!I->isAtomic()) + return false; + + if (auto *FI = dyn_cast(I)) + // All legal orderings for fence are stronger than monotonic. + return FI->getSyncScopeID() != SyncScope::SingleThread; + else if (isa(I) || isa(I)) + return true; + else if (auto *SI = dyn_cast(I)) + return !SI->isUnordered(); + else if (auto *LI = dyn_cast(I)) + return !LI->isUnordered(); + else { + llvm_unreachable("unknown atomic instruction?"); + } +} + /// Helper for non-Convergent inference predicate InstrBreaksAttribute. static bool InstrBreaksNonConvergent(Instruction &I, const SCCNodeSet &SCCNodes) { @@ -1264,19 +1287,25 @@ /// Helper for NoFree inference predicate InstrBreaksAttribute. static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes) { - CallBase *CB = dyn_cast(&I); - if (!CB) - return false; + if (I.isVolatile()) + return true; - if (CB->hasFnAttr(Attribute::NoFree)) - return false; + if (isOrderedAtomic(&I)) + return true; - // Speculatively assume in SCC. - if (Function *Callee = CB->getCalledFunction()) - if (SCCNodes.contains(Callee)) + if (CallBase *CB = dyn_cast(&I)) { + if (CB->hasFnAttr(Attribute::NoFree)) return false; - return true; + // Speculatively assume in SCC. + if (Function *Callee = CB->getCalledFunction()) + if (SCCNodes.contains(Callee)) + return false; + + return true; + } + + return false; } /// Attempt to remove convergent function attribute when possible. @@ -1476,29 +1505,6 @@ return Changed; } -// Return true if this is an atomic which has an ordering stronger than -// unordered. Note that this is different than the predicate we use in -// Attributor. Here we chose to be conservative and consider monotonic -// operations potentially synchronizing. We generally don't do much with -// monotonic operations, so this is simply risk reduction. -static bool isOrderedAtomic(Instruction *I) { - if (!I->isAtomic()) - return false; - - if (auto *FI = dyn_cast(I)) - // All legal orderings for fence are stronger than monotonic. - return FI->getSyncScopeID() != SyncScope::SingleThread; - else if (isa(I) || isa(I)) - return true; - else if (auto *SI = dyn_cast(I)) - return !SI->isUnordered(); - else if (auto *LI = dyn_cast(I)) - return !LI->isUnordered(); - else { - llvm_unreachable("unknown atomic instruction?"); - } -} - static bool InstrBreaksNoSync(Instruction &I, const SCCNodeSet &SCCNodes) { // Volatile may synchronize if (I.isVolatile()) diff --git a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll --- a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll +++ b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll @@ -260,9 +260,7 @@ } ; CHECK-LABEL: 'infer_func_attrs2' -; GLOBAL: %p -; POINT-NOT: %p -; FIXME: Can be inferred from attributes +; CHECK: %p define void @infer_func_attrs2(i32* dereferenceable(8) %p) readonly { call void @mayfree() %v = load i32, i32* %p diff --git a/llvm/test/Transforms/Attributor/dereferenceable-2-inseltpoison.ll b/llvm/test/Transforms/Attributor/dereferenceable-2-inseltpoison.ll --- a/llvm/test/Transforms/Attributor/dereferenceable-2-inseltpoison.ll +++ b/llvm/test/Transforms/Attributor/dereferenceable-2-inseltpoison.ll @@ -296,16 +296,16 @@ ; The 2nd and 3rd loads may never execute. define void @volatile_is_not_dereferenceable(i16* %ptr) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@volatile_is_not_dereferenceable -; IS__TUNIT____-SAME: (i16* nofree align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { +; IS__TUNIT____-SAME: (i16* align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { ; IS__TUNIT____-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i16, i16* [[PTR]], i64 0 ; IS__TUNIT____-NEXT: [[T0:%.*]] = load volatile i16, i16* [[ARRAYIDX0]], align 2 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@volatile_is_not_dereferenceable -; IS__CGSCC____-SAME: (i16* nofree align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { +; IS__CGSCC____-SAME: (i16* align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { ; IS__CGSCC____-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i16, i16* [[PTR]], i64 0 ; IS__CGSCC____-NEXT: [[T0:%.*]] = load volatile i16, i16* [[ARRAYIDX0]], align 2 ; IS__CGSCC____-NEXT: ret void @@ -849,12 +849,12 @@ ; IS__TUNIT____: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind readonly willreturn } ; IS__TUNIT____: attributes #[[ATTR1]] = { argmemonly nofree nosync nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR2]] = { nofree nosync nounwind readnone willreturn } -; IS__TUNIT____: attributes #[[ATTR3]] = { argmemonly nofree nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR3]] = { argmemonly nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR4]] = { argmemonly nofree nosync nounwind willreturn writeonly } ;. ; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind readonly willreturn } ; IS__CGSCC____: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR3]] = { argmemonly nofree norecurse nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR3]] = { argmemonly norecurse nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR4]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } ;. diff --git a/llvm/test/Transforms/Attributor/dereferenceable-2.ll b/llvm/test/Transforms/Attributor/dereferenceable-2.ll --- a/llvm/test/Transforms/Attributor/dereferenceable-2.ll +++ b/llvm/test/Transforms/Attributor/dereferenceable-2.ll @@ -296,16 +296,16 @@ ; The 2nd and 3rd loads may never execute. define void @volatile_is_not_dereferenceable(i16* %ptr) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@volatile_is_not_dereferenceable -; IS__TUNIT____-SAME: (i16* nofree align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { +; IS__TUNIT____-SAME: (i16* align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { ; IS__TUNIT____-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i16, i16* [[PTR]], i64 0 ; IS__TUNIT____-NEXT: [[T0:%.*]] = load volatile i16, i16* [[ARRAYIDX0]], align 2 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@volatile_is_not_dereferenceable -; IS__CGSCC____-SAME: (i16* nofree align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { +; IS__CGSCC____-SAME: (i16* align 2 [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { ; IS__CGSCC____-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i16, i16* [[PTR]], i64 0 ; IS__CGSCC____-NEXT: [[T0:%.*]] = load volatile i16, i16* [[ARRAYIDX0]], align 2 ; IS__CGSCC____-NEXT: ret void @@ -849,12 +849,12 @@ ; IS__TUNIT____: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind readonly willreturn } ; IS__TUNIT____: attributes #[[ATTR1]] = { argmemonly nofree nosync nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR2]] = { nofree nosync nounwind readnone willreturn } -; IS__TUNIT____: attributes #[[ATTR3]] = { argmemonly nofree nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR3]] = { argmemonly nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR4]] = { argmemonly nofree nosync nounwind willreturn writeonly } ;. ; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind readonly willreturn } ; IS__CGSCC____: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR3]] = { argmemonly nofree norecurse nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR3]] = { argmemonly norecurse nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR4]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } ;. diff --git a/llvm/test/Transforms/Attributor/liveness.ll b/llvm/test/Transforms/Attributor/liveness.ll --- a/llvm/test/Transforms/Attributor/liveness.ll +++ b/llvm/test/Transforms/Attributor/liveness.ll @@ -71,15 +71,15 @@ } define i32 @volatile_load(i32*) norecurse nounwind uwtable { -; NOT_CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn +; NOT_CGSCC_NPM: Function Attrs: argmemonly norecurse nounwind uwtable willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@volatile_load -; NOT_CGSCC_NPM-SAME: (i32* nofree align 4 [[TMP0:%.*]]) #[[ATTR6:[0-9]+]] { +; NOT_CGSCC_NPM-SAME: (i32* align 4 [[TMP0:%.*]]) #[[ATTR6:[0-9]+]] { ; NOT_CGSCC_NPM-NEXT: [[TMP2:%.*]] = load volatile i32, i32* [[TMP0]], align 4 ; NOT_CGSCC_NPM-NEXT: ret i32 [[TMP2]] ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind uwtable willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@volatile_load -; IS__CGSCC____-SAME: (i32* nofree align 4 [[TMP0:%.*]]) #[[ATTR7:[0-9]+]] { +; IS__CGSCC____-SAME: (i32* align 4 [[TMP0:%.*]]) #[[ATTR7:[0-9]+]] { ; IS__CGSCC____-NEXT: [[TMP2:%.*]] = load volatile i32, i32* [[TMP0]], align 4 ; IS__CGSCC____-NEXT: ret i32 [[TMP2]] ; @@ -2634,7 +2634,7 @@ ; NOT_CGSCC_NPM: attributes #[[ATTR3]] = { noreturn nounwind } ; NOT_CGSCC_NPM: attributes #[[ATTR4]] = { noreturn } ; NOT_CGSCC_NPM: attributes #[[ATTR5]] = { nosync readnone } -; NOT_CGSCC_NPM: attributes #[[ATTR6]] = { argmemonly nofree norecurse nounwind uwtable willreturn } +; NOT_CGSCC_NPM: attributes #[[ATTR6]] = { argmemonly norecurse nounwind uwtable willreturn } ; NOT_CGSCC_NPM: attributes #[[ATTR7]] = { nosync } ; NOT_CGSCC_NPM: attributes #[[ATTR8]] = { argmemonly nofree nosync nounwind willreturn writeonly } ; NOT_CGSCC_NPM: attributes #[[ATTR9]] = { nofree noreturn nosync nounwind readnone } @@ -2652,7 +2652,7 @@ ; IS__CGSCC____: attributes #[[ATTR4]] = { noreturn } ; IS__CGSCC____: attributes #[[ATTR5]] = { nosync readnone } ; IS__CGSCC____: attributes #[[ATTR6]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR7]] = { argmemonly nofree norecurse nounwind uwtable willreturn } +; IS__CGSCC____: attributes #[[ATTR7]] = { argmemonly norecurse nounwind uwtable willreturn } ; IS__CGSCC____: attributes #[[ATTR8]] = { nofree norecurse nosync nounwind readnone uwtable willreturn } ; IS__CGSCC____: attributes #[[ATTR9]] = { nosync } ; IS__CGSCC____: attributes #[[ATTR10]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } diff --git a/llvm/test/Transforms/Attributor/nocapture-1.ll b/llvm/test/Transforms/Attributor/nocapture-1.ll --- a/llvm/test/Transforms/Attributor/nocapture-1.ll +++ b/llvm/test/Transforms/Attributor/nocapture-1.ll @@ -537,15 +537,15 @@ } define void @test_cmpxchg(i32* %p) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test_cmpxchg -; IS__TUNIT____-SAME: (i32* nocapture nofree noundef nonnull dereferenceable(4) [[P:%.*]]) #[[ATTR9:[0-9]+]] { +; IS__TUNIT____-SAME: (i32* nocapture noundef nonnull dereferenceable(4) [[P:%.*]]) #[[ATTR9:[0-9]+]] { ; IS__TUNIT____-NEXT: [[TMP1:%.*]] = cmpxchg i32* [[P]], i32 0, i32 1 acquire monotonic, align 4 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test_cmpxchg -; IS__CGSCC____-SAME: (i32* nocapture nofree noundef nonnull dereferenceable(4) [[P:%.*]]) #[[ATTR9:[0-9]+]] { +; IS__CGSCC____-SAME: (i32* nocapture noundef nonnull dereferenceable(4) [[P:%.*]]) #[[ATTR9:[0-9]+]] { ; IS__CGSCC____-NEXT: [[TMP1:%.*]] = cmpxchg i32* [[P]], i32 0, i32 1 acquire monotonic, align 4 ; IS__CGSCC____-NEXT: ret void ; @@ -554,15 +554,15 @@ } define void @test_cmpxchg_ptr(i32** %p, i32* %q) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test_cmpxchg_ptr -; IS__TUNIT____-SAME: (i32** nocapture nofree noundef nonnull dereferenceable(8) [[P:%.*]], i32* nofree [[Q:%.*]]) #[[ATTR9]] { +; IS__TUNIT____-SAME: (i32** nocapture noundef nonnull dereferenceable(8) [[P:%.*]], i32* [[Q:%.*]]) #[[ATTR9]] { ; IS__TUNIT____-NEXT: [[TMP1:%.*]] = cmpxchg i32** [[P]], i32* null, i32* [[Q]] acquire monotonic, align 8 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test_cmpxchg_ptr -; IS__CGSCC____-SAME: (i32** nocapture nofree noundef nonnull dereferenceable(8) [[P:%.*]], i32* nofree [[Q:%.*]]) #[[ATTR9]] { +; IS__CGSCC____-SAME: (i32** nocapture noundef nonnull dereferenceable(8) [[P:%.*]], i32* [[Q:%.*]]) #[[ATTR9]] { ; IS__CGSCC____-NEXT: [[TMP1:%.*]] = cmpxchg i32** [[P]], i32* null, i32* [[Q]] acquire monotonic, align 8 ; IS__CGSCC____-NEXT: ret void ; @@ -571,15 +571,15 @@ } define void @test_atomicrmw(i32* %p) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test_atomicrmw -; IS__TUNIT____-SAME: (i32* nocapture nofree noundef nonnull dereferenceable(4) [[P:%.*]]) #[[ATTR9]] { +; IS__TUNIT____-SAME: (i32* nocapture noundef nonnull dereferenceable(4) [[P:%.*]]) #[[ATTR9]] { ; IS__TUNIT____-NEXT: [[TMP1:%.*]] = atomicrmw add i32* [[P]], i32 1 seq_cst, align 4 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test_atomicrmw -; IS__CGSCC____-SAME: (i32* nocapture nofree noundef nonnull dereferenceable(4) [[P:%.*]]) #[[ATTR9]] { +; IS__CGSCC____-SAME: (i32* nocapture noundef nonnull dereferenceable(4) [[P:%.*]]) #[[ATTR9]] { ; IS__CGSCC____-NEXT: [[TMP1:%.*]] = atomicrmw add i32* [[P]], i32 1 seq_cst, align 4 ; IS__CGSCC____-NEXT: ret void ; @@ -588,17 +588,17 @@ } define void @test_volatile(i32* %x) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test_volatile -; IS__TUNIT____-SAME: (i32* nofree align 4 [[X:%.*]]) #[[ATTR9]] { +; IS__TUNIT____-SAME: (i32* align 4 [[X:%.*]]) #[[ATTR9]] { ; IS__TUNIT____-NEXT: entry: ; IS__TUNIT____-NEXT: [[GEP:%.*]] = getelementptr i32, i32* [[X]], i64 1 ; IS__TUNIT____-NEXT: store volatile i32 0, i32* [[GEP]], align 4 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test_volatile -; IS__CGSCC____-SAME: (i32* nofree align 4 [[X:%.*]]) #[[ATTR9]] { +; IS__CGSCC____-SAME: (i32* align 4 [[X:%.*]]) #[[ATTR9]] { ; IS__CGSCC____-NEXT: entry: ; IS__CGSCC____-NEXT: [[GEP:%.*]] = getelementptr i32, i32* [[X]], i64 1 ; IS__CGSCC____-NEXT: store volatile i32 0, i32* [[GEP]], align 4 @@ -883,7 +883,7 @@ ; IS__TUNIT____: attributes #[[ATTR6]] = { argmemonly nounwind } ; IS__TUNIT____: attributes #[[ATTR7]] = { nofree nosync nounwind writeonly } ; IS__TUNIT____: attributes #[[ATTR8]] = { nofree noreturn nosync nounwind readnone willreturn } -; IS__TUNIT____: attributes #[[ATTR9]] = { argmemonly nofree nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR9]] = { argmemonly nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR10]] = { nofree nosync nounwind null_pointer_is_valid readnone willreturn } ; IS__TUNIT____: attributes #[[ATTR11:[0-9]+]] = { nounwind readonly willreturn } ; IS__TUNIT____: attributes #[[ATTR12]] = { nounwind willreturn } @@ -903,7 +903,7 @@ ; IS__CGSCC____: attributes #[[ATTR6]] = { argmemonly nounwind } ; IS__CGSCC____: attributes #[[ATTR7]] = { nofree nosync nounwind writeonly } ; IS__CGSCC____: attributes #[[ATTR8]] = { nofree norecurse noreturn nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR9]] = { argmemonly nofree norecurse nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR9]] = { argmemonly norecurse nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR10]] = { nofree nosync nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR11]] = { nofree nosync nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR12]] = { nofree norecurse nosync nounwind null_pointer_is_valid readnone willreturn } diff --git a/llvm/test/Transforms/Attributor/nofree.ll b/llvm/test/Transforms/Attributor/nofree.ll --- a/llvm/test/Transforms/Attributor/nofree.ll +++ b/llvm/test/Transforms/Attributor/nofree.ll @@ -270,13 +270,13 @@ ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@call_floor2 ; IS__TUNIT____-SAME: (float [[A:%.*]]) #[[ATTR3]] { -; IS__TUNIT____-NEXT: [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]]) #[[ATTR13:[0-9]+]] +; IS__TUNIT____-NEXT: [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]]) #[[ATTR14:[0-9]+]] ; IS__TUNIT____-NEXT: ret float [[C]] ; ; IS__CGSCC____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@call_floor2 ; IS__CGSCC____-SAME: (float [[A:%.*]]) #[[ATTR7:[0-9]+]] { -; IS__CGSCC____-NEXT: [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]]) #[[ATTR14:[0-9]+]] +; IS__CGSCC____-NEXT: [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]]) #[[ATTR15:[0-9]+]] ; IS__CGSCC____-NEXT: ret float [[C]] ; %c = tail call float @llvm.floor.f32(float %a) @@ -372,17 +372,17 @@ ret void } -; TEST 15: Use an acquire atomic (positive) +; TEST 15: Use an acquire atomic (negative) define void @test15(i8* %p) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test15 -; IS__TUNIT____-SAME: (i8* nocapture nofree noundef nonnull dereferenceable(1) [[P:%.*]]) #[[ATTR9:[0-9]+]] { +; IS__TUNIT____-SAME: (i8* nocapture noundef nonnull dereferenceable(1) [[P:%.*]]) #[[ATTR9:[0-9]+]] { ; IS__TUNIT____-NEXT: [[X:%.*]] = atomicrmw add i8* [[P]], i8 1 acquire, align 1 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test15 -; IS__CGSCC____-SAME: (i8* nocapture nofree noundef nonnull dereferenceable(1) [[P:%.*]]) #[[ATTR10:[0-9]+]] { +; IS__CGSCC____-SAME: (i8* nocapture noundef nonnull dereferenceable(1) [[P:%.*]]) #[[ATTR10:[0-9]+]] { ; IS__CGSCC____-NEXT: [[X:%.*]] = atomicrmw add i8* [[P]], i8 1 acquire, align 1 ; IS__CGSCC____-NEXT: ret void ; @@ -390,19 +390,17 @@ ret void } -; TEST 16: Use a release atomic (positive) -; TODO: Should this be negative? See discussion on https://reviews.llvm.org/D100676 -; and https://reviews.llvm.org/D101701. +; TEST 16: Use a release atomic (negative) define void @test16(i8* %p) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test16 -; IS__TUNIT____-SAME: (i8* nocapture nofree noundef nonnull dereferenceable(1) [[P:%.*]]) #[[ATTR9]] { +; IS__TUNIT____-SAME: (i8* nocapture noundef nonnull dereferenceable(1) [[P:%.*]]) #[[ATTR9]] { ; IS__TUNIT____-NEXT: [[X:%.*]] = atomicrmw add i8* [[P]], i8 1 release, align 1 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test16 -; IS__CGSCC____-SAME: (i8* nocapture nofree noundef nonnull dereferenceable(1) [[P:%.*]]) #[[ATTR10]] { +; IS__CGSCC____-SAME: (i8* nocapture noundef nonnull dereferenceable(1) [[P:%.*]]) #[[ATTR10]] { ; IS__CGSCC____-NEXT: [[X:%.*]] = atomicrmw add i8* [[P]], i8 1 release, align 1 ; IS__CGSCC____-NEXT: ret void ; @@ -417,13 +415,13 @@ ; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly ; IS__TUNIT____-LABEL: define {{[^@]+}}@test17 ; IS__TUNIT____-SAME: (i8* nocapture nofree writeonly [[P:%.*]], i8 [[VAL:%.*]]) #[[ATTR10:[0-9]+]] { -; IS__TUNIT____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[P]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR14:[0-9]+]] +; IS__TUNIT____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[P]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR15:[0-9]+]] ; IS__TUNIT____-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@test17 ; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[P:%.*]], i8 [[VAL:%.*]]) #[[ATTR11:[0-9]+]] { -; IS__CGSCC____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[P]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR15:[0-9]+]] +; IS__CGSCC____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[P]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR16:[0-9]+]] ; IS__CGSCC____-NEXT: ret void ; call void @llvm.memset(i8* %p, i8 %val, i32 8, i1 0) @@ -434,16 +432,16 @@ ; Should this be negative? See discussion on https://reviews.llvm.org/D100676 ; and https://reviews.llvm.org/D101701. define void @test18(i8* %p, i8 %val) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly +; IS__TUNIT____: Function Attrs: argmemonly nosync nounwind willreturn writeonly ; IS__TUNIT____-LABEL: define {{[^@]+}}@test18 -; IS__TUNIT____-SAME: (i8* nocapture nofree writeonly [[P:%.*]], i8 [[VAL:%.*]]) #[[ATTR10]] { -; IS__TUNIT____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[P]], i8 [[VAL]], i32 noundef 8, i1 noundef true) #[[ATTR14]] +; IS__TUNIT____-SAME: (i8* nocapture nofree writeonly [[P:%.*]], i8 [[VAL:%.*]]) #[[ATTR11:[0-9]+]] { +; IS__TUNIT____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[P]], i8 [[VAL]], i32 noundef 8, i1 noundef true) #[[ATTR15]] ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly +; IS__CGSCC____: Function Attrs: argmemonly nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@test18 -; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[P:%.*]], i8 [[VAL:%.*]]) #[[ATTR11]] { -; IS__CGSCC____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[P]], i8 [[VAL]], i32 noundef 8, i1 noundef true) #[[ATTR15]] +; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[P:%.*]], i8 [[VAL:%.*]]) #[[ATTR12:[0-9]+]] { +; IS__CGSCC____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[P]], i8 [[VAL]], i32 noundef 8, i1 noundef true) #[[ATTR16]] ; IS__CGSCC____-NEXT: ret void ; call void @llvm.memset(i8* %p, i8 %val, i32 8, i1 1) @@ -461,13 +459,13 @@ ; ; IS__TUNIT____-LABEL: define {{[^@]+}}@nonnull_assume_pos ; IS__TUNIT____-SAME: (i8* nofree [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* nofree [[ARG3:%.*]], i8* [[ARG4:%.*]]) { -; IS__TUNIT____-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR15:[0-9]+]] [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ] +; IS__TUNIT____-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16:[0-9]+]] [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ] ; IS__TUNIT____-NEXT: call void @unknown(i8* nofree [[ARG1]], i8* [[ARG2]], i8* nofree [[ARG3]], i8* [[ARG4]]) ; IS__TUNIT____-NEXT: ret void ; ; IS__CGSCC____-LABEL: define {{[^@]+}}@nonnull_assume_pos ; IS__CGSCC____-SAME: (i8* nofree [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* nofree [[ARG3:%.*]], i8* [[ARG4:%.*]]) { -; IS__CGSCC____-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR16:[0-9]+]] [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ] +; IS__CGSCC____-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR17:[0-9]+]] [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ] ; IS__CGSCC____-NEXT: call void @unknown(i8* nofree [[ARG1]], i8* [[ARG2]], i8* nofree [[ARG3]], i8* [[ARG4]]) ; IS__CGSCC____-NEXT: ret void ; @@ -556,13 +554,14 @@ ; IS__TUNIT____: attributes #[[ATTR6:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn } ; IS__TUNIT____: attributes #[[ATTR7]] = { nofree nounwind } ; IS__TUNIT____: attributes #[[ATTR8:[0-9]+]] = { nobuiltin nofree nounwind } -; IS__TUNIT____: attributes #[[ATTR9]] = { argmemonly nofree nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR9]] = { argmemonly nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR10]] = { argmemonly nofree nosync nounwind willreturn writeonly } -; IS__TUNIT____: attributes #[[ATTR11:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn } -; IS__TUNIT____: attributes #[[ATTR12:[0-9]+]] = { nounwind willreturn } -; IS__TUNIT____: attributes #[[ATTR13]] = { readnone willreturn } -; IS__TUNIT____: attributes #[[ATTR14]] = { willreturn writeonly } -; IS__TUNIT____: attributes #[[ATTR15]] = { willreturn } +; IS__TUNIT____: attributes #[[ATTR11]] = { argmemonly nosync nounwind willreturn writeonly } +; IS__TUNIT____: attributes #[[ATTR12:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR14]] = { readnone willreturn } +; IS__TUNIT____: attributes #[[ATTR15]] = { willreturn writeonly } +; IS__TUNIT____: attributes #[[ATTR16]] = { willreturn } ;. ; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nounwind } ; IS__CGSCC_OPM: attributes #[[ATTR1]] = { noinline nounwind uwtable } @@ -574,13 +573,14 @@ ; IS__CGSCC_OPM: attributes #[[ATTR7]] = { nofree noinline nosync nounwind readnone uwtable willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR8]] = { nofree nounwind } ; IS__CGSCC_OPM: attributes #[[ATTR9:[0-9]+]] = { nobuiltin nofree nounwind } -; IS__CGSCC_OPM: attributes #[[ATTR10]] = { argmemonly nofree norecurse nounwind willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR10]] = { argmemonly norecurse nounwind willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR11]] = { argmemonly nofree nosync nounwind willreturn writeonly } -; IS__CGSCC_OPM: attributes #[[ATTR12:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR14]] = { readnone willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR15]] = { willreturn writeonly } -; IS__CGSCC_OPM: attributes #[[ATTR16]] = { willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR12]] = { argmemonly nosync nounwind willreturn writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR13:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR14:[0-9]+]] = { nounwind willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR15]] = { readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR16]] = { willreturn writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR17]] = { willreturn } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nounwind } ; IS__CGSCC_NPM: attributes #[[ATTR1]] = { noinline nounwind uwtable } @@ -592,11 +592,12 @@ ; IS__CGSCC_NPM: attributes #[[ATTR7]] = { nofree noinline nosync nounwind readnone uwtable willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR8]] = { nofree nounwind } ; IS__CGSCC_NPM: attributes #[[ATTR9:[0-9]+]] = { nobuiltin nofree nounwind } -; IS__CGSCC_NPM: attributes #[[ATTR10]] = { argmemonly nofree norecurse nounwind willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR10]] = { argmemonly norecurse nounwind willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR11]] = { argmemonly nofree nosync nounwind willreturn writeonly } -; IS__CGSCC_NPM: attributes #[[ATTR12:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR13:[0-9]+]] = { nounwind willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR14]] = { readnone willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR15]] = { willreturn writeonly } -; IS__CGSCC_NPM: attributes #[[ATTR16]] = { willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR12]] = { argmemonly nosync nounwind willreturn writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR13:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR14:[0-9]+]] = { nounwind willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR15]] = { readnone willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR16]] = { willreturn writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR17]] = { willreturn } ;. diff --git a/llvm/test/Transforms/Attributor/nosync.ll b/llvm/test/Transforms/Attributor/nosync.ll --- a/llvm/test/Transforms/Attributor/nosync.ll +++ b/llvm/test/Transforms/Attributor/nosync.ll @@ -95,9 +95,9 @@ ; } define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn +; CHECK: Function Attrs: argmemonly norecurse nounwind uwtable willreturn ; CHECK-LABEL: define {{[^@]+}}@load_acquire -; CHECK-SAME: (i32* nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[TMP0:%.*]]) #[[ATTR2:[0-9]+]] { +; CHECK-SAME: (i32* nocapture noundef nonnull readonly align 4 dereferenceable(4) [[TMP0:%.*]]) #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0]] acquire, align 4 ; CHECK-NEXT: ret i32 [[TMP2]] ; @@ -112,9 +112,9 @@ ; } define void @load_release(i32* nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn +; CHECK: Function Attrs: argmemonly norecurse nounwind uwtable willreturn ; CHECK-LABEL: define {{[^@]+}}@load_release -; CHECK-SAME: (i32* nocapture nofree noundef writeonly align 4 [[TMP0:%.*]]) #[[ATTR2]] { +; CHECK-SAME: (i32* nocapture noundef writeonly align 4 [[TMP0:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0]] release, align 4 ; CHECK-NEXT: ret void ; @@ -125,9 +125,9 @@ ; TEST 6 - negative volatile, relaxed atomic define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn +; CHECK: Function Attrs: argmemonly norecurse nounwind uwtable willreturn ; CHECK-LABEL: define {{[^@]+}}@load_volatile_release -; CHECK-SAME: (i32* nocapture nofree noundef writeonly align 4 [[TMP0:%.*]]) #[[ATTR2]] { +; CHECK-SAME: (i32* nocapture noundef writeonly align 4 [[TMP0:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0]] release, align 4 ; CHECK-NEXT: ret void ; @@ -142,9 +142,9 @@ ; } define void @volatile_store(i32* %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn +; CHECK: Function Attrs: argmemonly norecurse nounwind uwtable willreturn ; CHECK-LABEL: define {{[^@]+}}@volatile_store -; CHECK-SAME: (i32* nofree noundef align 4 [[TMP0:%.*]]) #[[ATTR2]] { +; CHECK-SAME: (i32* noundef align 4 [[TMP0:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: store volatile i32 14, i32* [[TMP0]], align 4 ; CHECK-NEXT: ret void ; @@ -160,9 +160,9 @@ ; } define i32 @volatile_load(i32* %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn +; CHECK: Function Attrs: argmemonly norecurse nounwind uwtable willreturn ; CHECK-LABEL: define {{[^@]+}}@volatile_load -; CHECK-SAME: (i32* nofree align 4 [[TMP0:%.*]]) #[[ATTR2]] { +; CHECK-SAME: (i32* align 4 [[TMP0:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, i32* [[TMP0]], align 4 ; CHECK-NEXT: ret i32 [[TMP2]] ; @@ -258,18 +258,18 @@ %"struct.std::__atomic_base" = type { i8 } define void @foo1(i32* %0, %"struct.std::atomic"* %1) { -; IS__TUNIT____: Function Attrs: nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@foo1 -; IS__TUNIT____-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR6:[0-9]+]] { +; IS__TUNIT____-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR6:[0-9]+]] { ; IS__TUNIT____-NEXT: store i32 100, i32* [[TMP0]], align 4 ; IS__TUNIT____-NEXT: fence release ; IS__TUNIT____-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0 ; IS__TUNIT____-NEXT: store atomic i8 1, i8* [[TMP3]] monotonic, align 1 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@foo1 -; IS__CGSCC____-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR6:[0-9]+]] { +; IS__CGSCC____-SAME: (i32* nocapture noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR6:[0-9]+]] { ; IS__CGSCC____-NEXT: store i32 100, i32* [[TMP0]], align 4 ; IS__CGSCC____-NEXT: fence release ; IS__CGSCC____-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0 @@ -284,9 +284,9 @@ } define void @bar(i32* %0, %"struct.std::atomic"* %1) { -; IS__TUNIT____: Function Attrs: nofree nounwind +; IS__TUNIT____: Function Attrs: nounwind ; IS__TUNIT____-LABEL: define {{[^@]+}}@bar -; IS__TUNIT____-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR7:[0-9]+]] { +; IS__TUNIT____-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nonnull readonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR7:[0-9]+]] { ; IS__TUNIT____-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0 ; IS__TUNIT____-NEXT: br label [[TMP4:%.*]] ; IS__TUNIT____: 4: @@ -298,9 +298,9 @@ ; IS__TUNIT____-NEXT: fence acquire ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind +; IS__CGSCC____: Function Attrs: norecurse nounwind ; IS__CGSCC____-LABEL: define {{[^@]+}}@bar -; IS__CGSCC____-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR7:[0-9]+]] { +; IS__CGSCC____-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nonnull readonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR7:[0-9]+]] { ; IS__CGSCC____-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0 ; IS__CGSCC____-NEXT: br label [[TMP4:%.*]] ; IS__CGSCC____: 4: @@ -404,16 +404,16 @@ ; It is odd to add nocapture but a result of the llvm.memcpy nocapture. ; define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nosync nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@memcpy_volatile ; IS__TUNIT____-SAME: (i8* nocapture nofree writeonly [[PTR1:%.*]], i8* nocapture nofree readonly [[PTR2:%.*]]) #[[ATTR10:[0-9]+]] { ; IS__TUNIT____-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[PTR1]], i8* noalias nocapture nofree readonly [[PTR2]], i32 noundef 8, i1 noundef true) #[[ATTR17:[0-9]+]] ; IS__TUNIT____-NEXT: ret i32 4 ; -; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly nosync nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@memcpy_volatile ; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[PTR1:%.*]], i8* nocapture nofree readonly [[PTR2:%.*]]) #[[ATTR10:[0-9]+]] { -; IS__CGSCC____-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[PTR1]], i8* noalias nocapture nofree readonly [[PTR2]], i32 noundef 8, i1 noundef true) #[[ATTR18:[0-9]+]] +; IS__CGSCC____-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[PTR1]], i8* noalias nocapture nofree readonly [[PTR2]], i32 noundef 8, i1 noundef true) #[[ATTR19:[0-9]+]] ; IS__CGSCC____-NEXT: ret i32 4 ; call void @llvm.memcpy(i8* %ptr1, i8* %ptr2, i32 8, i1 1) @@ -434,7 +434,7 @@ ; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@memset_non_volatile ; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[PTR1:%.*]], i8 [[VAL:%.*]]) #[[ATTR11:[0-9]+]] { -; IS__CGSCC____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[PTR1]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR19:[0-9]+]] +; IS__CGSCC____-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[PTR1]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR20:[0-9]+]] ; IS__CGSCC____-NEXT: ret i32 4 ; call void @llvm.memset(i8* %ptr1, i8 %val, i32 8, i1 0) @@ -475,11 +475,17 @@ ; TEST 18 - negative. Synchronizing intrinsic define void @i_totally_sync() { -; CHECK: Function Attrs: nounwind -; CHECK-LABEL: define {{[^@]+}}@i_totally_sync -; CHECK-SAME: () #[[ATTR14:[0-9]+]] { -; CHECK-NEXT: tail call void @llvm.x86.sse2.clflush(i8* noundef nonnull align 4 dereferenceable(4) bitcast (i32* @a to i8*)) -; CHECK-NEXT: ret void +; IS__TUNIT____: Function Attrs: nounwind +; IS__TUNIT____-LABEL: define {{[^@]+}}@i_totally_sync +; IS__TUNIT____-SAME: () #[[ATTR7]] { +; IS__TUNIT____-NEXT: tail call void @llvm.x86.sse2.clflush(i8* noundef nonnull align 4 dereferenceable(4) bitcast (i32* @a to i8*)) +; IS__TUNIT____-NEXT: ret void +; +; IS__CGSCC____: Function Attrs: nounwind +; IS__CGSCC____-LABEL: define {{[^@]+}}@i_totally_sync +; IS__CGSCC____-SAME: () #[[ATTR14:[0-9]+]] { +; IS__CGSCC____-NEXT: tail call void @llvm.x86.sse2.clflush(i8* noundef nonnull align 4 dereferenceable(4) bitcast (i32* @a to i8*)) +; IS__CGSCC____-NEXT: ret void ; tail call void @llvm.x86.sse2.clflush(i8* bitcast (i32* @a to i8*)) ret void @@ -492,7 +498,7 @@ define i32 @cos_test(float %x) { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@cos_test -; IS__TUNIT____-SAME: (float [[X:%.*]]) #[[ATTR15:[0-9]+]] { +; IS__TUNIT____-SAME: (float [[X:%.*]]) #[[ATTR14:[0-9]+]] { ; IS__TUNIT____-NEXT: ret i32 4 ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn @@ -507,14 +513,14 @@ define float @cos_test2(float %x) { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@cos_test2 -; IS__TUNIT____-SAME: (float [[X:%.*]]) #[[ATTR15]] { +; IS__TUNIT____-SAME: (float [[X:%.*]]) #[[ATTR14]] { ; IS__TUNIT____-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X]]) #[[ATTR19:[0-9]+]] ; IS__TUNIT____-NEXT: ret float [[C]] ; ; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@cos_test2 ; IS__CGSCC____-SAME: (float [[X:%.*]]) #[[ATTR16:[0-9]+]] { -; IS__CGSCC____-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X]]) #[[ATTR20:[0-9]+]] +; IS__CGSCC____-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X]]) #[[ATTR21:[0-9]+]] ; IS__CGSCC____-NEXT: ret float [[C]] ; %c = call float @llvm.cos(float %x) @@ -523,20 +529,20 @@ ;. ; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind optsize readnone ssp uwtable willreturn } ; IS__TUNIT____: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind uwtable willreturn } -; IS__TUNIT____: attributes #[[ATTR2]] = { argmemonly nofree norecurse nounwind uwtable willreturn } +; IS__TUNIT____: attributes #[[ATTR2]] = { argmemonly norecurse nounwind uwtable willreturn } ; IS__TUNIT____: attributes #[[ATTR3]] = { noinline nosync nounwind uwtable } ; IS__TUNIT____: attributes #[[ATTR4]] = { noinline nounwind uwtable } ; IS__TUNIT____: attributes #[[ATTR5]] = { nofree noinline noreturn nosync nounwind readnone uwtable willreturn } -; IS__TUNIT____: attributes #[[ATTR6]] = { nofree nounwind willreturn } -; IS__TUNIT____: attributes #[[ATTR7]] = { nofree nounwind } +; IS__TUNIT____: attributes #[[ATTR6]] = { nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR7]] = { nounwind } ; IS__TUNIT____: attributes #[[ATTR8]] = { nofree nosync nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR9]] = { nofree nosync nounwind } -; IS__TUNIT____: attributes #[[ATTR10]] = { argmemonly nofree nosync nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR10]] = { argmemonly nosync nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR11]] = { argmemonly nofree nosync nounwind willreturn writeonly } ; IS__TUNIT____: attributes #[[ATTR12:[0-9]+]] = { convergent readnone } ; IS__TUNIT____: attributes #[[ATTR13]] = { readnone } -; IS__TUNIT____: attributes #[[ATTR14]] = { nounwind } -; IS__TUNIT____: attributes #[[ATTR15]] = { nofree nosync nounwind readnone willreturn } +; IS__TUNIT____: attributes #[[ATTR14]] = { nofree nosync nounwind readnone willreturn } +; IS__TUNIT____: attributes #[[ATTR15:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR16:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn } ; IS__TUNIT____: attributes #[[ATTR17]] = { willreturn } ; IS__TUNIT____: attributes #[[ATTR18]] = { willreturn writeonly } @@ -544,45 +550,47 @@ ;. ; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind optsize readnone ssp uwtable willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind uwtable willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR2]] = { argmemonly nofree norecurse nounwind uwtable willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR2]] = { argmemonly norecurse nounwind uwtable willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR3]] = { noinline nosync nounwind uwtable } ; IS__CGSCC_OPM: attributes #[[ATTR4]] = { noinline nounwind uwtable } ; IS__CGSCC_OPM: attributes #[[ATTR5]] = { nofree noinline noreturn nosync nounwind readnone uwtable willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR6]] = { nofree norecurse nounwind willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR7]] = { nofree norecurse nounwind } +; IS__CGSCC_OPM: attributes #[[ATTR6]] = { norecurse nounwind willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR7]] = { norecurse nounwind } ; IS__CGSCC_OPM: attributes #[[ATTR8]] = { nofree norecurse nosync nounwind willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind } -; IS__CGSCC_OPM: attributes #[[ATTR10]] = { argmemonly nofree nosync nounwind willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR10]] = { argmemonly nosync nounwind willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR11]] = { argmemonly nofree nosync nounwind willreturn writeonly } ; IS__CGSCC_OPM: attributes #[[ATTR12:[0-9]+]] = { convergent readnone } ; IS__CGSCC_OPM: attributes #[[ATTR13]] = { readnone } ; IS__CGSCC_OPM: attributes #[[ATTR14]] = { nounwind } ; IS__CGSCC_OPM: attributes #[[ATTR15]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR16]] = { nofree nosync nounwind readnone willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR17:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR18]] = { willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR19]] = { willreturn writeonly } -; IS__CGSCC_OPM: attributes #[[ATTR20]] = { readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR17:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR18:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR19]] = { willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR20]] = { willreturn writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR21]] = { readnone willreturn } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind optsize readnone ssp uwtable willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind uwtable willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR2]] = { argmemonly nofree norecurse nounwind uwtable willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR2]] = { argmemonly norecurse nounwind uwtable willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR3]] = { noinline nosync nounwind uwtable } ; IS__CGSCC_NPM: attributes #[[ATTR4]] = { noinline nounwind uwtable } ; IS__CGSCC_NPM: attributes #[[ATTR5]] = { nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR6]] = { nofree norecurse nounwind willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR7]] = { nofree norecurse nounwind } +; IS__CGSCC_NPM: attributes #[[ATTR6]] = { norecurse nounwind willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR7]] = { norecurse nounwind } ; IS__CGSCC_NPM: attributes #[[ATTR8]] = { nofree norecurse nosync nounwind willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind } -; IS__CGSCC_NPM: attributes #[[ATTR10]] = { argmemonly nofree nosync nounwind willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR10]] = { argmemonly nosync nounwind willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR11]] = { argmemonly nofree nosync nounwind willreturn writeonly } ; IS__CGSCC_NPM: attributes #[[ATTR12:[0-9]+]] = { convergent readnone } ; IS__CGSCC_NPM: attributes #[[ATTR13]] = { readnone } ; IS__CGSCC_NPM: attributes #[[ATTR14]] = { nounwind } ; IS__CGSCC_NPM: attributes #[[ATTR15]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR16]] = { nofree nosync nounwind readnone willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR17:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR18]] = { willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR19]] = { willreturn writeonly } -; IS__CGSCC_NPM: attributes #[[ATTR20]] = { readnone willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR17:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR18:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR19]] = { willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR20]] = { willreturn writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR21]] = { readnone willreturn } ;. diff --git a/llvm/test/Transforms/Attributor/readattrs.ll b/llvm/test/Transforms/Attributor/readattrs.ll --- a/llvm/test/Transforms/Attributor/readattrs.ll +++ b/llvm/test/Transforms/Attributor/readattrs.ll @@ -241,15 +241,15 @@ } define i32 @volatile_load(i32* %p) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nounwind willreturn +; IS__TUNIT____: Function Attrs: argmemonly nounwind willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@volatile_load -; IS__TUNIT____-SAME: (i32* nofree noundef align 4 [[P:%.*]]) #[[ATTR7:[0-9]+]] { +; IS__TUNIT____-SAME: (i32* noundef align 4 [[P:%.*]]) #[[ATTR7:[0-9]+]] { ; IS__TUNIT____-NEXT: [[LOAD:%.*]] = load volatile i32, i32* [[P]], align 4 ; IS__TUNIT____-NEXT: ret i32 [[LOAD]] ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind willreturn +; IS__CGSCC____: Function Attrs: argmemonly norecurse nounwind willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@volatile_load -; IS__CGSCC____-SAME: (i32* nofree noundef align 4 [[P:%.*]]) #[[ATTR8:[0-9]+]] { +; IS__CGSCC____-SAME: (i32* noundef align 4 [[P:%.*]]) #[[ATTR8:[0-9]+]] { ; IS__CGSCC____-NEXT: [[LOAD:%.*]] = load volatile i32, i32* [[P]], align 4 ; IS__CGSCC____-NEXT: ret i32 [[LOAD]] ; @@ -500,7 +500,7 @@ ; IS__TUNIT____: attributes #[[ATTR4]] = { nofree nosync nounwind readonly willreturn } ; IS__TUNIT____: attributes #[[ATTR5]] = { argmemonly nounwind readonly } ; IS__TUNIT____: attributes #[[ATTR6]] = { argmemonly nounwind } -; IS__TUNIT____: attributes #[[ATTR7]] = { argmemonly nofree nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR7]] = { argmemonly nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR8]] = { readnone } ; IS__TUNIT____: attributes #[[ATTR9]] = { nounwind readonly } ; IS__TUNIT____: attributes #[[ATTR10]] = { willreturn writeonly } @@ -515,7 +515,7 @@ ; IS__CGSCC____: attributes #[[ATTR5]] = { nofree nosync nounwind readonly willreturn } ; IS__CGSCC____: attributes #[[ATTR6]] = { argmemonly nounwind readonly } ; IS__CGSCC____: attributes #[[ATTR7]] = { argmemonly nounwind } -; IS__CGSCC____: attributes #[[ATTR8]] = { argmemonly nofree norecurse nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR8]] = { argmemonly norecurse nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR9]] = { readnone } ; IS__CGSCC____: attributes #[[ATTR10]] = { nounwind readonly } ; IS__CGSCC____: attributes #[[ATTR11]] = { readnone willreturn } diff --git a/llvm/test/Transforms/Attributor/undefined_behavior.ll b/llvm/test/Transforms/Attributor/undefined_behavior.ll --- a/llvm/test/Transforms/Attributor/undefined_behavior.ll +++ b/llvm/test/Transforms/Attributor/undefined_behavior.ll @@ -196,12 +196,12 @@ ; -- AtomicRMW tests -- define void @atomicrmw_wholly_unreachable() { -; IS__TUNIT____: Function Attrs: nofree nounwind readnone willreturn +; IS__TUNIT____: Function Attrs: nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@atomicrmw_wholly_unreachable ; IS__TUNIT____-SAME: () #[[ATTR3:[0-9]+]] { ; IS__TUNIT____-NEXT: unreachable ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind readnone willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@atomicrmw_wholly_unreachable ; IS__CGSCC____-SAME: () #[[ATTR3:[0-9]+]] { ; IS__CGSCC____-NEXT: unreachable @@ -211,7 +211,7 @@ } define void @atomicrmw_single_bb_unreachable(i1 %cond) { -; IS__TUNIT____: Function Attrs: nofree nounwind readnone willreturn +; IS__TUNIT____: Function Attrs: nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@atomicrmw_single_bb_unreachable ; IS__TUNIT____-SAME: (i1 [[COND:%.*]]) #[[ATTR3]] { ; IS__TUNIT____-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]] @@ -220,7 +220,7 @@ ; IS__TUNIT____: e: ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind readnone willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@atomicrmw_single_bb_unreachable ; IS__CGSCC____-SAME: (i1 [[COND:%.*]]) #[[ATTR3]] { ; IS__CGSCC____-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]] @@ -238,13 +238,13 @@ } define void @atomicrmw_null_pointer_is_defined() null_pointer_is_valid { -; IS__TUNIT____: Function Attrs: nofree nounwind null_pointer_is_valid willreturn +; IS__TUNIT____: Function Attrs: nounwind null_pointer_is_valid willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@atomicrmw_null_pointer_is_defined ; IS__TUNIT____-SAME: () #[[ATTR4:[0-9]+]] { ; IS__TUNIT____-NEXT: [[A:%.*]] = atomicrmw add i32* null, i32 1 acquire, align 4 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind null_pointer_is_valid willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind null_pointer_is_valid willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@atomicrmw_null_pointer_is_defined ; IS__CGSCC____-SAME: () #[[ATTR4:[0-9]+]] { ; IS__CGSCC____-NEXT: [[A:%.*]] = atomicrmw add i32* null, i32 1 acquire, align 4 @@ -258,12 +258,12 @@ ; ATTRIBUTOR-LABEL: @atomicrmw_null_propagated( ; ATTRIBUTOR-NEXT: unreachable ; -; IS__TUNIT____: Function Attrs: nofree nounwind readnone willreturn +; IS__TUNIT____: Function Attrs: nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@atomicrmw_null_propagated ; IS__TUNIT____-SAME: () #[[ATTR3]] { ; IS__TUNIT____-NEXT: unreachable ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind readnone willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@atomicrmw_null_propagated ; IS__CGSCC____-SAME: () #[[ATTR3]] { ; IS__CGSCC____-NEXT: unreachable @@ -276,12 +276,12 @@ ; -- AtomicCmpXchg tests -- define void @atomiccmpxchg_wholly_unreachable() { -; IS__TUNIT____: Function Attrs: nofree nounwind readnone willreturn +; IS__TUNIT____: Function Attrs: nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@atomiccmpxchg_wholly_unreachable ; IS__TUNIT____-SAME: () #[[ATTR3]] { ; IS__TUNIT____-NEXT: unreachable ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind readnone willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@atomiccmpxchg_wholly_unreachable ; IS__CGSCC____-SAME: () #[[ATTR3]] { ; IS__CGSCC____-NEXT: unreachable @@ -291,7 +291,7 @@ } define void @atomiccmpxchg_single_bb_unreachable(i1 %cond) { -; IS__TUNIT____: Function Attrs: nofree nounwind readnone willreturn +; IS__TUNIT____: Function Attrs: nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@atomiccmpxchg_single_bb_unreachable ; IS__TUNIT____-SAME: (i1 [[COND:%.*]]) #[[ATTR3]] { ; IS__TUNIT____-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]] @@ -300,7 +300,7 @@ ; IS__TUNIT____: e: ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind readnone willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@atomiccmpxchg_single_bb_unreachable ; IS__CGSCC____-SAME: (i1 [[COND:%.*]]) #[[ATTR3]] { ; IS__CGSCC____-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]] @@ -318,13 +318,13 @@ } define void @atomiccmpxchg_null_pointer_is_defined() null_pointer_is_valid { -; IS__TUNIT____: Function Attrs: nofree nounwind null_pointer_is_valid willreturn +; IS__TUNIT____: Function Attrs: nounwind null_pointer_is_valid willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@atomiccmpxchg_null_pointer_is_defined ; IS__TUNIT____-SAME: () #[[ATTR4]] { ; IS__TUNIT____-NEXT: [[A:%.*]] = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic, align 4 ; IS__TUNIT____-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind null_pointer_is_valid willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind null_pointer_is_valid willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@atomiccmpxchg_null_pointer_is_defined ; IS__CGSCC____-SAME: () #[[ATTR4]] { ; IS__CGSCC____-NEXT: [[A:%.*]] = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic, align 4 @@ -338,12 +338,12 @@ ; ATTRIBUTOR-LABEL: @atomiccmpxchg_null_propagated( ; ATTRIBUTOR-NEXT: unreachable ; -; IS__TUNIT____: Function Attrs: nofree nounwind readnone willreturn +; IS__TUNIT____: Function Attrs: nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@atomiccmpxchg_null_propagated ; IS__TUNIT____-SAME: () #[[ATTR3]] { ; IS__TUNIT____-NEXT: unreachable ; -; IS__CGSCC____: Function Attrs: nofree norecurse nounwind readnone willreturn +; IS__CGSCC____: Function Attrs: norecurse nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@atomiccmpxchg_null_propagated ; IS__CGSCC____-SAME: () #[[ATTR3]] { ; IS__CGSCC____-NEXT: unreachable @@ -1129,8 +1129,8 @@ ; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn } ; IS__TUNIT____: attributes #[[ATTR1]] = { nofree nosync nounwind null_pointer_is_valid readnone willreturn } ; IS__TUNIT____: attributes #[[ATTR2]] = { nofree nosync nounwind null_pointer_is_valid willreturn writeonly } -; IS__TUNIT____: attributes #[[ATTR3]] = { nofree nounwind readnone willreturn } -; IS__TUNIT____: attributes #[[ATTR4]] = { nofree nounwind null_pointer_is_valid willreturn } +; IS__TUNIT____: attributes #[[ATTR3]] = { nounwind readnone willreturn } +; IS__TUNIT____: attributes #[[ATTR4]] = { nounwind null_pointer_is_valid willreturn } ; IS__TUNIT____: attributes #[[ATTR5]] = { nofree noreturn nosync nounwind readnone willreturn } ; IS__TUNIT____: attributes #[[ATTR6]] = { argmemonly nofree nosync nounwind willreturn writeonly } ; IS__TUNIT____: attributes #[[ATTR7]] = { nofree nosync nounwind willreturn writeonly } @@ -1138,8 +1138,8 @@ ; IS__CGSCC____: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind null_pointer_is_valid readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind null_pointer_is_valid willreturn writeonly } -; IS__CGSCC____: attributes #[[ATTR3]] = { nofree norecurse nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR4]] = { nofree norecurse nounwind null_pointer_is_valid willreturn } +; IS__CGSCC____: attributes #[[ATTR3]] = { norecurse nounwind readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR4]] = { norecurse nounwind null_pointer_is_valid willreturn } ; IS__CGSCC____: attributes #[[ATTR5]] = { nofree norecurse noreturn nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR6]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR7]] = { nounwind willreturn writeonly } diff --git a/llvm/test/Transforms/FunctionAttrs/atomic.ll b/llvm/test/Transforms/FunctionAttrs/atomic.ll --- a/llvm/test/Transforms/FunctionAttrs/atomic.ll +++ b/llvm/test/Transforms/FunctionAttrs/atomic.ll @@ -20,8 +20,7 @@ ret i32 %r } -; TODO: Should a function with a Release store be nofree? See discussion on -; https://reviews.llvm.org/D100676 and https://reviews.llvm.org/D101701. +; A function with a Release store is not nofree. define void @test3(i32* %x) uwtable ssp { ; CHECK: define void @test3(i32* nocapture %x) #1 { entry: @@ -30,4 +29,4 @@ } ; CHECK: attributes #0 = { nofree norecurse nosync nounwind readnone ssp uwtable willreturn mustprogress } -; CHECK: attributes #1 = { nofree norecurse nounwind ssp uwtable willreturn mustprogress } +; CHECK: attributes #1 = { norecurse nounwind ssp uwtable willreturn mustprogress } diff --git a/llvm/test/Transforms/FunctionAttrs/nofree.ll b/llvm/test/Transforms/FunctionAttrs/nofree.ll --- a/llvm/test/Transforms/FunctionAttrs/nofree.ll +++ b/llvm/test/Transforms/FunctionAttrs/nofree.ll @@ -182,7 +182,7 @@ } define void @memset_volatile(i8* %p, i8 %val) { -; CHECK: Function Attrs: nofree nounwind willreturn writeonly mustprogress +; CHECK: Function Attrs: nounwind willreturn writeonly mustprogress ; CHECK-LABEL: @memset_volatile( ; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* [[P:%.*]], i8 [[VAL:%.*]], i32 8, i1 true) ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/FunctionAttrs/nosync.ll b/llvm/test/Transforms/FunctionAttrs/nosync.ll --- a/llvm/test/Transforms/FunctionAttrs/nosync.ll +++ b/llvm/test/Transforms/FunctionAttrs/nosync.ll @@ -49,7 +49,7 @@ ; negative case - explicit sync define void @test5(i8* %p) { -; CHECK: Function Attrs: nofree norecurse nounwind willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind willreturn mustprogress ; CHECK-LABEL: @test5( ; CHECK-NEXT: store atomic i8 0, i8* [[P:%.*]] seq_cst, align 1 ; CHECK-NEXT: ret void @@ -60,7 +60,7 @@ ; negative case - explicit sync define i8 @test6(i8* %p) { -; CHECK: Function Attrs: nofree norecurse nounwind willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind willreturn mustprogress ; CHECK-LABEL: @test6( ; CHECK-NEXT: [[V:%.*]] = load atomic i8, i8* [[P:%.*]] seq_cst, align 1 ; CHECK-NEXT: ret i8 [[V]] @@ -71,7 +71,7 @@ ; negative case - explicit sync define void @test7(i8* %p) { -; CHECK: Function Attrs: nofree norecurse nounwind willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind willreturn mustprogress ; CHECK-LABEL: @test7( ; CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add i8* [[P:%.*]], i8 0 seq_cst, align 1 ; CHECK-NEXT: ret void @@ -82,7 +82,7 @@ ; negative case - explicit sync define void @test8(i8* %p) { -; CHECK: Function Attrs: nofree norecurse nounwind willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind willreturn mustprogress ; CHECK-LABEL: @test8( ; CHECK-NEXT: fence seq_cst ; CHECK-NEXT: ret void @@ -104,7 +104,7 @@ ; atomic load with monotonic ordering define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind uwtable willreturn mustprogress ; CHECK-LABEL: @load_monotonic( ; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0:%.*]] monotonic, align 4 ; CHECK-NEXT: ret i32 [[TMP2]] @@ -115,7 +115,7 @@ ; atomic store with monotonic ordering. define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind uwtable willreturn mustprogress ; CHECK-LABEL: @store_monotonic( ; CHECK-NEXT: store atomic i32 10, i32* [[TMP0:%.*]] monotonic, align 4 ; CHECK-NEXT: ret void @@ -127,7 +127,7 @@ ; negative, should not deduce nosync ; atomic load with acquire ordering. define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind uwtable willreturn mustprogress ; CHECK-LABEL: @load_acquire( ; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0:%.*]] acquire, align 4 ; CHECK-NEXT: ret i32 [[TMP2]] @@ -161,7 +161,7 @@ ; negative, should not deduce nosync ; atomic load with release ordering define void @load_release(i32* nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind uwtable willreturn mustprogress ; CHECK-LABEL: @load_release( ; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0:%.*]] release, align 4 ; CHECK-NEXT: ret void @@ -172,7 +172,7 @@ ; negative volatile, relaxed atomic define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind uwtable willreturn mustprogress ; CHECK-LABEL: @load_volatile_release( ; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0:%.*]] release, align 4 ; CHECK-NEXT: ret void @@ -183,7 +183,7 @@ ; volatile store. define void @volatile_store(i32* %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind uwtable willreturn mustprogress ; CHECK-LABEL: @volatile_store( ; CHECK-NEXT: store volatile i32 14, i32* [[TMP0:%.*]], align 4 ; CHECK-NEXT: ret void @@ -195,7 +195,7 @@ ; negative, should not deduce nosync ; volatile load. define i32 @volatile_load(i32* %0) norecurse nounwind uwtable { -; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn mustprogress +; CHECK: Function Attrs: norecurse nounwind uwtable willreturn mustprogress ; CHECK-LABEL: @volatile_load( ; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, i32* [[TMP0:%.*]], align 4 ; CHECK-NEXT: ret i32 [[TMP2]]