diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -102,6 +102,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/Triple.h" #include "llvm/Analysis/AssumeBundleQueries.h" #include "llvm/Analysis/CFG.h" #include "llvm/Analysis/CGSCCPassManager.h" @@ -806,7 +807,7 @@ [&](const Function &F) { return AG.getAnalysis(F); }), - AG(AG), CGSCC(CGSCC) { + AG(AG), CGSCC(CGSCC), TargetTriple(M.getTargetTriple()) { if (CGSCC) initializeModuleSlice(*CGSCC); } @@ -956,6 +957,16 @@ return ModuleSlice.count(const_cast(&F)); } + /// Return true if the stack (llvm::Alloca) can be accessed by other threads. + bool stackIsAccessibleByOtherThreads() { + return !targetIsGPU(); + } + + /// Return true if the target is a GPU. + bool targetIsGPU() { + return TargetTriple.isAMDGPU() || TargetTriple.isNVPTX(); + } + private: struct FunctionInfo { ~FunctionInfo(); @@ -1019,6 +1030,9 @@ DenseMap, bool> PotentiallyReachableMap; + /// The triple describing the target machine. + Triple TargetTriple; + /// Give the Attributor access to the members so /// Attributor::identifyDefaultAbstractAttributes(...) can initialize them. friend struct Attributor; 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 @@ -2347,8 +2347,8 @@ (!getAssociatedFunction() || !getAssociatedFunction()->mustProgress())) return false; - const auto &MemAA = A.getAAFor(*this, getIRPosition(), - DepClassTy::NONE); + const auto &MemAA = + A.getAAFor(*this, getIRPosition(), DepClassTy::NONE); if (!MemAA.isAssumedReadOnly()) return false; if (KnownOnly && !MemAA.isKnownReadOnly()) @@ -5063,7 +5063,8 @@ : AAHeapToStack(IRP, A) {} const std::string getAsStr() const override { - return "[H2S] Mallocs: " + std::to_string(MallocCalls.size()); + return "[H2S] Mallocs: " + std::to_string(MallocCalls.size()) + "/" + + std::to_string(BadMallocCalls.size()); } ChangeStatus manifest(Attributor &A) override { @@ -5162,10 +5163,29 @@ MustBeExecutedContextExplorer &Explorer = A.getInfoCache().getMustBeExecutedContextExplorer(); + bool StackIsAccessibleByOtherThreads = + A.getInfoCache().stackIsAccessibleByOtherThreads(); + auto FreeCheck = [&](Instruction &I) { + // If the stack is not accessible by other threads, the "must-free" logic + // doesn't apply as the pointer could be shared and needs to be places in + // "sharable" memory. + if (!StackIsAccessibleByOtherThreads) { + auto &NoSyncAA = + A.getAAFor(*this, getIRPosition(), DepClassTy::OPTIONAL); + if (!NoSyncAA.isAssumedNoSync()) { + LLVM_DEBUG( + dbgs() << "[H2S] found an escaping use, stack is not accessible by " + "other threads and function is not nosync:\n"); + return false; + } + } const auto &Frees = FreesForMalloc.lookup(&I); - if (Frees.size() != 1) + if (Frees.size() != 1) { + LLVM_DEBUG(dbgs() << "[H2S] did not find one free call but " + << Frees.size() << "\n"); return false; + } Instruction *UniqueFree = *Frees.begin(); return Explorer.findInContextOf(UniqueFree, I.getNextNode()); }; @@ -5206,12 +5226,12 @@ const auto &NoCaptureAA = A.getAAFor( *this, IRPosition::callsite_argument(*CB, ArgNo), - DepClassTy::REQUIRED); + DepClassTy::OPTIONAL); // If a callsite argument use is nofree, we are fine. const auto &ArgNoFreeAA = A.getAAFor( *this, IRPosition::callsite_argument(*CB, ArgNo), - DepClassTy::REQUIRED); + DepClassTy::OPTIONAL); if (!NoCaptureAA.isAssumedNoCapture() || !ArgNoFreeAA.isAssumedNoFree()) { diff --git a/llvm/test/Transforms/Attributor/heap_to_stack.ll b/llvm/test/Transforms/Attributor/heap_to_stack.ll --- a/llvm/test/Transforms/Attributor/heap_to_stack.ll +++ b/llvm/test/Transforms/Attributor/heap_to_stack.ll @@ -29,8 +29,9 @@ declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) nounwind define void @nofree_arg_only(i8* %p1, i8* %p2) { +; CHECK: Function Attrs: nosync ; CHECK-LABEL: define {{[^@]+}}@nofree_arg_only -; CHECK-SAME: (i8* nocapture nofree [[P1:%.*]], i8* nocapture [[P2:%.*]]) { +; CHECK-SAME: (i8* nocapture nofree [[P1:%.*]], i8* nocapture [[P2:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: tail call void @free(i8* nocapture [[P2]]) ; CHECK-NEXT: tail call void @nofree_func(i8* nocapture nofree [[P1]]) ; CHECK-NEXT: ret void @@ -75,13 +76,17 @@ ; TEST 3 - 1 malloc, 1 free define void @test3() { -; IS________OPM-LABEL: define {{[^@]+}}@test3() { +; IS________OPM: Function Attrs: nosync +; IS________OPM-LABEL: define {{[^@]+}}@test3 +; IS________OPM-SAME: () #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________OPM-NEXT: tail call void @free(i8* noalias nocapture [[TMP1]]) ; IS________OPM-NEXT: ret void ; -; IS________NPM-LABEL: define {{[^@]+}}@test3() { +; IS________NPM: Function Attrs: nosync +; IS________NPM-LABEL: define {{[^@]+}}@test3 +; IS________NPM-SAME: () #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 ; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________NPM-NEXT: ret void @@ -93,18 +98,35 @@ } define void @test3a(i8* %p) { -; IS________OPM-LABEL: define {{[^@]+}}@test3a -; IS________OPM-SAME: (i8* nocapture [[P:%.*]]) { -; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; IS________OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP1]], i8* nocapture [[P]]) -; IS________OPM-NEXT: tail call void @free(i8* noalias nocapture [[TMP1]]) -; IS________OPM-NEXT: ret void -; -; IS________NPM-LABEL: define {{[^@]+}}@test3a -; IS________NPM-SAME: (i8* nocapture [[P:%.*]]) { -; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 -; IS________NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP1]], i8* nocapture [[P]]) -; IS________NPM-NEXT: ret void +; IS__TUNIT_OPM: Function Attrs: nosync +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test3a +; IS__TUNIT_OPM-SAME: (i8* nocapture [[P:%.*]]) #[[ATTR0]] { +; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; IS__TUNIT_OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP1]], i8* nocapture [[P]]) #[[ATTR0]] +; IS__TUNIT_OPM-NEXT: tail call void @free(i8* noalias nocapture [[TMP1]]) +; IS__TUNIT_OPM-NEXT: ret void +; +; IS__TUNIT_NPM: Function Attrs: nosync +; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test3a +; IS__TUNIT_NPM-SAME: (i8* nocapture [[P:%.*]]) #[[ATTR0]] { +; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 +; IS__TUNIT_NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP1]], i8* nocapture [[P]]) #[[ATTR0]] +; IS__TUNIT_NPM-NEXT: ret void +; +; IS__CGSCC_OPM: Function Attrs: nosync +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test3a +; IS__CGSCC_OPM-SAME: (i8* nocapture [[P:%.*]]) #[[ATTR0]] { +; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; IS__CGSCC_OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP1]], i8* nocapture [[P]]) +; IS__CGSCC_OPM-NEXT: tail call void @free(i8* noalias nocapture [[TMP1]]) +; IS__CGSCC_OPM-NEXT: ret void +; +; IS__CGSCC_NPM: Function Attrs: nosync +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test3a +; IS__CGSCC_NPM-SAME: (i8* nocapture [[P:%.*]]) #[[ATTR0]] { +; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 +; IS__CGSCC_NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP1]], i8* nocapture [[P]]) +; IS__CGSCC_NPM-NEXT: ret void ; %1 = tail call noalias i8* @malloc(i64 4) tail call void @nofree_arg_only(i8* %1, i8* %p) @@ -171,12 +193,16 @@ ; TEST 4 define void @test4() { -; IS________OPM-LABEL: define {{[^@]+}}@test4() { +; IS________OPM: Function Attrs: nosync +; IS________OPM-LABEL: define {{[^@]+}}@test4 +; IS________OPM-SAME: () #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________OPM-NEXT: ret void ; -; IS________NPM-LABEL: define {{[^@]+}}@test4() { +; IS________NPM: Function Attrs: nosync +; IS________NPM-LABEL: define {{[^@]+}}@test4 +; IS________NPM-SAME: () #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 ; IS________NPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________NPM-NEXT: ret void @@ -190,34 +216,67 @@ ; are in nofree functions and are not captured define void @test5(i32, i8* %p) { -; IS________OPM-LABEL: define {{[^@]+}}@test5 -; IS________OPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]]) { -; IS________OPM-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; IS________OPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 -; IS________OPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] -; IS________OPM: 4: -; IS________OPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP2]]) -; IS________OPM-NEXT: br label [[TMP6:%.*]] -; IS________OPM: 5: -; IS________OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP2]], i8* nocapture [[P]]) -; IS________OPM-NEXT: tail call void @free(i8* noalias nocapture [[TMP2]]) -; IS________OPM-NEXT: br label [[TMP6]] -; IS________OPM: 6: -; IS________OPM-NEXT: ret void -; -; IS________NPM-LABEL: define {{[^@]+}}@test5 -; IS________NPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]]) { -; IS________NPM-NEXT: [[TMP2:%.*]] = alloca i8, i64 4, align 1 -; IS________NPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 -; IS________NPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] -; IS________NPM: 4: -; IS________NPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP2]]) -; IS________NPM-NEXT: br label [[TMP6:%.*]] -; IS________NPM: 5: -; IS________NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP2]], i8* nocapture [[P]]) -; IS________NPM-NEXT: br label [[TMP6]] -; IS________NPM: 6: -; IS________NPM-NEXT: ret void +; IS__TUNIT_OPM: Function Attrs: nosync +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test5 +; IS__TUNIT_OPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]]) #[[ATTR0]] { +; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 +; IS__TUNIT_OPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] +; IS__TUNIT_OPM: 4: +; IS__TUNIT_OPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP2]]) +; IS__TUNIT_OPM-NEXT: br label [[TMP6:%.*]] +; IS__TUNIT_OPM: 5: +; IS__TUNIT_OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP2]], i8* nocapture [[P]]) #[[ATTR0]] +; IS__TUNIT_OPM-NEXT: tail call void @free(i8* noalias nocapture [[TMP2]]) +; IS__TUNIT_OPM-NEXT: br label [[TMP6]] +; IS__TUNIT_OPM: 6: +; IS__TUNIT_OPM-NEXT: ret void +; +; IS__TUNIT_NPM: Function Attrs: nosync +; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test5 +; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]]) #[[ATTR0]] { +; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca i8, i64 4, align 1 +; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 +; IS__TUNIT_NPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] +; IS__TUNIT_NPM: 4: +; IS__TUNIT_NPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP2]]) +; IS__TUNIT_NPM-NEXT: br label [[TMP6:%.*]] +; IS__TUNIT_NPM: 5: +; IS__TUNIT_NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP2]], i8* nocapture [[P]]) #[[ATTR0]] +; IS__TUNIT_NPM-NEXT: br label [[TMP6]] +; IS__TUNIT_NPM: 6: +; IS__TUNIT_NPM-NEXT: ret void +; +; IS__CGSCC_OPM: Function Attrs: nosync +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test5 +; IS__CGSCC_OPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]]) #[[ATTR0]] { +; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 +; IS__CGSCC_OPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] +; IS__CGSCC_OPM: 4: +; IS__CGSCC_OPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP2]]) +; IS__CGSCC_OPM-NEXT: br label [[TMP6:%.*]] +; IS__CGSCC_OPM: 5: +; IS__CGSCC_OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP2]], i8* nocapture [[P]]) +; IS__CGSCC_OPM-NEXT: tail call void @free(i8* noalias nocapture [[TMP2]]) +; IS__CGSCC_OPM-NEXT: br label [[TMP6]] +; IS__CGSCC_OPM: 6: +; IS__CGSCC_OPM-NEXT: ret void +; +; IS__CGSCC_NPM: Function Attrs: nosync +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test5 +; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]]) #[[ATTR0]] { +; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca i8, i64 4, align 1 +; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 +; IS__CGSCC_NPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] +; IS__CGSCC_NPM: 4: +; IS__CGSCC_NPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP2]]) +; IS__CGSCC_NPM-NEXT: br label [[TMP6:%.*]] +; IS__CGSCC_NPM: 5: +; IS__CGSCC_NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP2]], i8* nocapture [[P]]) +; IS__CGSCC_NPM-NEXT: br label [[TMP6]] +; IS__CGSCC_NPM: 6: +; IS__CGSCC_NPM-NEXT: ret void ; %2 = tail call noalias i8* @malloc(i64 4) %3 = icmp eq i32 %0, 0 @@ -239,8 +298,9 @@ ; TEST 6 - all exit paths have a call to free define void @test6(i32) { +; IS________OPM: Function Attrs: nosync ; IS________OPM-LABEL: define {{[^@]+}}@test6 -; IS________OPM-SAME: (i32 [[TMP0:%.*]]) { +; IS________OPM-SAME: (i32 [[TMP0:%.*]]) #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 ; IS________OPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] @@ -254,8 +314,9 @@ ; IS________OPM: 6: ; IS________OPM-NEXT: ret void ; +; IS________NPM: Function Attrs: nosync ; IS________NPM-LABEL: define {{[^@]+}}@test6 -; IS________NPM-SAME: (i32 [[TMP0:%.*]]) { +; IS________NPM-SAME: (i32 [[TMP0:%.*]]) #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP2:%.*]] = alloca i8, i64 4, align 1 ; IS________NPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 ; IS________NPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] @@ -289,16 +350,16 @@ define void @test7() { ; IS________OPM: Function Attrs: noreturn ; IS________OPM-LABEL: define {{[^@]+}}@test7 -; IS________OPM-SAME: () #[[ATTR3:[0-9]+]] { +; IS________OPM-SAME: () #[[ATTR4:[0-9]+]] { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; IS________OPM-NEXT: [[TMP2:%.*]] = tail call i32 @no_return_call() #[[ATTR3]] +; IS________OPM-NEXT: [[TMP2:%.*]] = tail call i32 @no_return_call() #[[ATTR4]] ; IS________OPM-NEXT: unreachable ; ; IS________NPM: Function Attrs: noreturn ; IS________NPM-LABEL: define {{[^@]+}}@test7 -; IS________NPM-SAME: () #[[ATTR3:[0-9]+]] { +; IS________NPM-SAME: () #[[ATTR4:[0-9]+]] { ; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 -; IS________NPM-NEXT: [[TMP2:%.*]] = tail call i32 @no_return_call() #[[ATTR3]] +; IS________NPM-NEXT: [[TMP2:%.*]] = tail call i32 @no_return_call() #[[ATTR4]] ; IS________NPM-NEXT: unreachable ; %1 = tail call noalias i8* @malloc(i64 4) @@ -336,7 +397,7 @@ ; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________OPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32* ; IS________OPM-NEXT: store i32 10, i32* [[TMP2]], align 4 -; IS________OPM-NEXT: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR5:[0-9]+]] +; IS________OPM-NEXT: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR6:[0-9]+]] ; IS________OPM-NEXT: tail call void @free(i8* nocapture noundef nonnull align 4 dereferenceable(4) [[TMP1]]) ; IS________OPM-NEXT: ret void ; @@ -345,7 +406,7 @@ ; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________NPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32* ; IS________NPM-NEXT: store i32 10, i32* [[TMP2]], align 4 -; IS________NPM-NEXT: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR6:[0-9]+]] +; IS________NPM-NEXT: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR7:[0-9]+]] ; IS________NPM-NEXT: tail call void @free(i8* nocapture noundef nonnull align 4 dereferenceable(4) [[TMP1]]) ; IS________NPM-NEXT: ret void ; @@ -362,7 +423,9 @@ ; TEST 10 - 1 malloc, 1 free define i32 @test10() { -; IS________OPM-LABEL: define {{[^@]+}}@test10() { +; IS________OPM: Function Attrs: nosync +; IS________OPM-LABEL: define {{[^@]+}}@test10 +; IS________OPM-SAME: () #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________OPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32* @@ -371,7 +434,9 @@ ; IS________OPM-NEXT: tail call void @free(i8* noalias nocapture noundef nonnull align 4 dereferenceable(4) [[TMP1]]) ; IS________OPM-NEXT: ret i32 [[TMP3]] ; -; IS________NPM-LABEL: define {{[^@]+}}@test10() { +; IS________NPM: Function Attrs: nosync +; IS________NPM-LABEL: define {{[^@]+}}@test10 +; IS________NPM-SAME: () #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 ; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________NPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32* @@ -389,7 +454,9 @@ } define i32 @test_lifetime() { -; IS________OPM-LABEL: define {{[^@]+}}@test_lifetime() { +; IS________OPM: Function Attrs: nosync +; IS________OPM-LABEL: define {{[^@]+}}@test_lifetime +; IS________OPM-SAME: () #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________OPM-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[TMP1]]) @@ -399,7 +466,9 @@ ; IS________OPM-NEXT: tail call void @free(i8* noalias nocapture noundef nonnull align 4 dereferenceable(4) [[TMP1]]) ; IS________OPM-NEXT: ret i32 [[TMP3]] ; -; IS________NPM-LABEL: define {{[^@]+}}@test_lifetime() { +; IS________NPM: Function Attrs: nosync +; IS________NPM-LABEL: define {{[^@]+}}@test_lifetime +; IS________NPM-SAME: () #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 ; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; IS________NPM-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[TMP1]]) @@ -423,13 +492,13 @@ define void @test11() { ; IS________OPM-LABEL: define {{[^@]+}}@test11() { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; IS________OPM-NEXT: tail call void @sync_will_return(i8* [[TMP1]]) #[[ATTR5]] +; IS________OPM-NEXT: tail call void @sync_will_return(i8* [[TMP1]]) #[[ATTR6]] ; IS________OPM-NEXT: tail call void @free(i8* nocapture [[TMP1]]) ; IS________OPM-NEXT: ret void ; ; IS________NPM-LABEL: define {{[^@]+}}@test11() { ; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 -; IS________NPM-NEXT: tail call void @sync_will_return(i8* [[TMP1]]) #[[ATTR6]] +; IS________NPM-NEXT: tail call void @sync_will_return(i8* [[TMP1]]) #[[ATTR7]] ; IS________NPM-NEXT: ret void ; %1 = tail call noalias i8* @malloc(i64 4) @@ -440,8 +509,9 @@ ; TEST 12 define i32 @irreducible_cfg(i32 %0) { +; IS________OPM: Function Attrs: nosync ; IS________OPM-LABEL: define {{[^@]+}}@irreducible_cfg -; IS________OPM-SAME: (i32 [[TMP0:%.*]]) { +; IS________OPM-SAME: (i32 [[TMP0:%.*]]) #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP2:%.*]] = call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32* ; IS________OPM-NEXT: store i32 10, i32* [[TMP3]], align 4 @@ -466,14 +536,14 @@ ; IS________OPM-NEXT: [[TMP14]] = add nsw i32 [[DOT1]], 1 ; IS________OPM-NEXT: br label [[TMP8]] ; IS________OPM: 15: -; IS________OPM-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4 -; IS________OPM-NEXT: [[TMP17:%.*]] = bitcast i32* [[TMP3]] to i8* -; IS________OPM-NEXT: call void @free(i8* nocapture noundef [[TMP17]]) -; IS________OPM-NEXT: [[TMP18:%.*]] = load i32, i32* [[TMP3]], align 4 -; IS________OPM-NEXT: ret i32 [[TMP18]] +; IS________OPM-NEXT: [[TMP16:%.*]] = bitcast i32* [[TMP3]] to i8* +; IS________OPM-NEXT: call void @free(i8* nocapture noundef [[TMP16]]) +; IS________OPM-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4 +; IS________OPM-NEXT: ret i32 [[TMP17]] ; +; IS________NPM: Function Attrs: nosync ; IS________NPM-LABEL: define {{[^@]+}}@irreducible_cfg -; IS________NPM-SAME: (i32 [[TMP0:%.*]]) { +; IS________NPM-SAME: (i32 [[TMP0:%.*]]) #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP2:%.*]] = alloca i8, i64 4, align 1 ; IS________NPM-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32* ; IS________NPM-NEXT: store i32 10, i32* [[TMP3]], align 4 @@ -541,8 +611,9 @@ define i32 @malloc_in_loop(i32 %0) { +; IS________OPM: Function Attrs: nosync ; IS________OPM-LABEL: define {{[^@]+}}@malloc_in_loop -; IS________OPM-SAME: (i32 [[TMP0:%.*]]) { +; IS________OPM-SAME: (i32 [[TMP0:%.*]]) #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP2:%.*]] = alloca i32, align 4 ; IS________OPM-NEXT: [[TMP3:%.*]] = alloca i32*, align 8 ; IS________OPM-NEXT: store i32 [[TMP0]], i32* [[TMP2]], align 4 @@ -561,8 +632,9 @@ ; IS________OPM: 11: ; IS________OPM-NEXT: ret i32 5 ; +; IS________NPM: Function Attrs: nosync ; IS________NPM-LABEL: define {{[^@]+}}@malloc_in_loop -; IS________NPM-SAME: (i32 [[TMP0:%.*]]) { +; IS________NPM-SAME: (i32 [[TMP0:%.*]]) #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP2:%.*]] = alloca i32, align 4 ; IS________NPM-NEXT: [[TMP3:%.*]] = alloca i32*, align 8 ; IS________NPM-NEXT: store i32 [[TMP0]], i32* [[TMP2]], align 4 @@ -605,7 +677,9 @@ ; Malloc/Calloc too large define i32 @test13() { -; CHECK-LABEL: define {{[^@]+}}@test13() { +; CHECK: Function Attrs: nosync +; CHECK-LABEL: define {{[^@]+}}@test13 +; CHECK-SAME: () #[[ATTR0]] { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 256) ; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32* @@ -624,7 +698,9 @@ } define i32 @test_sle() { -; CHECK-LABEL: define {{[^@]+}}@test_sle() { +; CHECK: Function Attrs: nosync +; CHECK-LABEL: define {{[^@]+}}@test_sle +; CHECK-SAME: () #[[ATTR0]] { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef -1) ; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32* @@ -675,8 +751,9 @@ } define void @test15(i64 %S) { +; CHECK: Function Attrs: nosync ; CHECK-LABEL: define {{[^@]+}}@test15 -; CHECK-SAME: (i64 [[S:%.*]]) { +; CHECK-SAME: (i64 [[S:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 [[S]]) ; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) ; CHECK-NEXT: tail call void @free(i8* noalias nocapture [[TMP1]]) @@ -689,16 +766,18 @@ } define void @test16a(i8 %v, i8** %P) { +; IS________OPM: Function Attrs: nosync ; IS________OPM-LABEL: define {{[^@]+}}@test16a -; IS________OPM-SAME: (i8 [[V:%.*]], i8** nocapture nofree readnone [[P:%.*]]) { +; IS________OPM-SAME: (i8 [[V:%.*]], i8** nocapture nofree readnone [[P:%.*]]) #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: store i8 [[V]], i8* [[TMP1]], align 1 ; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree noundef nonnull dereferenceable(1) [[TMP1]]) ; IS________OPM-NEXT: tail call void @free(i8* noalias nocapture noundef nonnull dereferenceable(1) [[TMP1]]) ; IS________OPM-NEXT: ret void ; +; IS________NPM: Function Attrs: nosync ; IS________NPM-LABEL: define {{[^@]+}}@test16a -; IS________NPM-SAME: (i8 [[V:%.*]], i8** nocapture nofree readnone [[P:%.*]]) { +; IS________NPM-SAME: (i8 [[V:%.*]], i8** nocapture nofree readnone [[P:%.*]]) #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 ; IS________NPM-NEXT: store i8 [[V]], i8* [[TMP1]], align 1 ; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree noundef nonnull dereferenceable(1) [[TMP1]]) @@ -712,8 +791,9 @@ } define void @test16b(i8 %v, i8** %P) { +; CHECK: Function Attrs: nosync ; CHECK-LABEL: define {{[^@]+}}@test16b -; CHECK-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]]) { +; CHECK-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: store i8* [[TMP1]], i8** [[P]], align 8 ; CHECK-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]]) @@ -728,19 +808,21 @@ } define void @test16c(i8 %v, i8** %P) { +; IS________OPM: Function Attrs: nosync ; IS________OPM-LABEL: define {{[^@]+}}@test16c -; IS________OPM-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]]) { +; IS________OPM-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]]) #[[ATTR0]] { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: store i8* [[TMP1]], i8** [[P]], align 8 -; IS________OPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]]) #[[ATTR5]] +; IS________OPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]]) #[[ATTR6]] ; IS________OPM-NEXT: tail call void @free(i8* nocapture [[TMP1]]) ; IS________OPM-NEXT: ret void ; +; IS________NPM: Function Attrs: nosync ; IS________NPM-LABEL: define {{[^@]+}}@test16c -; IS________NPM-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]]) { +; IS________NPM-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]]) #[[ATTR0]] { ; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4, align 1 ; IS________NPM-NEXT: store i8* [[TMP1]], i8** [[P]], align 8 -; IS________NPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]]) #[[ATTR6]] +; IS________NPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]]) #[[ATTR7]] ; IS________NPM-NEXT: ret void ; %1 = tail call noalias i8* @malloc(i64 4) @@ -751,8 +833,9 @@ } define void @test16d(i8 %v, i8** %P) { +; CHECK: Function Attrs: nosync ; CHECK-LABEL: define {{[^@]+}}@test16d -; CHECK-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]]) { +; CHECK-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; CHECK-NEXT: store i8* [[TMP1]], i8** [[P]], align 8 ; CHECK-NEXT: ret void @@ -762,18 +845,20 @@ ret void } ;. -; IS________OPM: attributes #[[ATTR0:[0-9]+]] = { nounwind willreturn } -; IS________OPM: attributes #[[ATTR1:[0-9]+]] = { nofree nosync willreturn } -; IS________OPM: attributes #[[ATTR2:[0-9]+]] = { nofree nounwind } -; IS________OPM: attributes #[[ATTR3]] = { noreturn } -; IS________OPM: attributes #[[ATTR4:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn } -; IS________OPM: attributes #[[ATTR5]] = { nounwind } +; IS________OPM: attributes #[[ATTR0]] = { nosync } +; IS________OPM: attributes #[[ATTR1:[0-9]+]] = { nounwind willreturn } +; IS________OPM: attributes #[[ATTR2:[0-9]+]] = { nofree nosync willreturn } +; IS________OPM: attributes #[[ATTR3:[0-9]+]] = { nofree nounwind } +; IS________OPM: attributes #[[ATTR4]] = { noreturn } +; IS________OPM: attributes #[[ATTR5:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn } +; IS________OPM: attributes #[[ATTR6]] = { nounwind } ;. -; IS________NPM: attributes #[[ATTR0:[0-9]+]] = { nounwind willreturn } -; IS________NPM: attributes #[[ATTR1:[0-9]+]] = { nofree nosync willreturn } -; IS________NPM: attributes #[[ATTR2:[0-9]+]] = { nofree nounwind } -; IS________NPM: attributes #[[ATTR3]] = { noreturn } -; IS________NPM: attributes #[[ATTR4:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn } -; IS________NPM: attributes #[[ATTR5:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn writeonly } -; IS________NPM: attributes #[[ATTR6]] = { nounwind } +; IS________NPM: attributes #[[ATTR0]] = { nosync } +; IS________NPM: attributes #[[ATTR1:[0-9]+]] = { nounwind willreturn } +; IS________NPM: attributes #[[ATTR2:[0-9]+]] = { nofree nosync willreturn } +; IS________NPM: attributes #[[ATTR3:[0-9]+]] = { nofree nounwind } +; IS________NPM: attributes #[[ATTR4]] = { noreturn } +; IS________NPM: attributes #[[ATTR5:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn } +; IS________NPM: attributes #[[ATTR6:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn writeonly } +; IS________NPM: attributes #[[ATTR7]] = { nounwind } ;.