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 @@ -1015,11 +1015,13 @@ /// the abstract attributes. /// \param CGUpdater Helper to update an underlying call graph. /// \param Allowed If not null, a set limiting the attribute opportunities. + /// \param DeleteFns Whether to delete functions Attributor(SetVector &Functions, InformationCache &InfoCache, CallGraphUpdater &CGUpdater, - DenseSet *Allowed = nullptr) + DenseSet *Allowed = nullptr, bool DeleteFns = true) : Allocator(InfoCache.Allocator), Functions(Functions), - InfoCache(InfoCache), CGUpdater(CGUpdater), Allowed(Allowed) {} + InfoCache(InfoCache), CGUpdater(CGUpdater), Allowed(Allowed), + DeleteFns(DeleteFns) {} ~Attributor(); @@ -1656,6 +1658,9 @@ /// If not null, a set limiting the attribute opportunities. const DenseSet *Allowed; + /// Whether to delete functions + const bool DeleteFns; + /// A set to remember the functions we already assume to be live and visited. DenseSet VisitedFunctions; diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -1211,9 +1211,10 @@ } } - for (unsigned u = 0, e = InternalFns.size(); u < e; ++u) - if (Function *F = InternalFns[u]) - ToBeDeletedFunctions.insert(F); + if (DeleteFns) + for (unsigned u = 0, e = InternalFns.size(); u < e; ++u) + if (Function *F = InternalFns[u]) + ToBeDeletedFunctions.insert(F); } ChangeStatus Attributor::cleanupIR() { @@ -2288,7 +2289,8 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache, SetVector &Functions, AnalysisGetter &AG, - CallGraphUpdater &CGUpdater) { + CallGraphUpdater &CGUpdater, + bool DeleteFns) { if (Functions.empty()) return false; @@ -2297,7 +2299,8 @@ // Create an Attributor and initially empty information cache that is filled // while we identify default attribute opportunities. - Attributor A(Functions, InfoCache, CGUpdater); + Attributor A(Functions, InfoCache, CGUpdater, /* Allowed */ nullptr, + DeleteFns); // Create shallow wrappers for all functions that are not IPO amendable if (AllowShallowWrappers) @@ -2400,7 +2403,8 @@ CallGraphUpdater CGUpdater; BumpPtrAllocator Allocator; InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ nullptr); - if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater)) { + if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater, + /* DeleteFns */ true)) { // FIXME: Think about passes we will preserve and add them here. return PreservedAnalyses::none(); } @@ -2427,7 +2431,8 @@ CGUpdater.initialize(CG, C, AM, UR); BumpPtrAllocator Allocator; InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions); - if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater)) { + if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater, + /* DeleteFns */ false)) { // FIXME: Think about passes we will preserve and add them here. PreservedAnalyses PA; PA.preserve(); @@ -2502,7 +2507,8 @@ CallGraphUpdater CGUpdater; BumpPtrAllocator Allocator; InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ nullptr); - return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater); + return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater, + /* DeleteFns*/ true); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -2538,7 +2544,8 @@ Module &M = *Functions.back()->getParent(); BumpPtrAllocator Allocator; InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions); - return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater); + return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater, + /* DeleteFns */ false); } void getAnalysisUsage(AnalysisUsage &AU) const override { diff --git a/llvm/test/Transforms/Attributor/nodelete.ll b/llvm/test/Transforms/Attributor/nodelete.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Attributor/nodelete.ll @@ -0,0 +1,81 @@ +; RUN: opt -attributor-cgscc -S < %s | FileCheck %s + +%"a" = type { i64 } +%"b" = type { i8 } + +define hidden i64 @f1() align 2 { +entry: + %ref.tmp = alloca %"a", align 8 + %call2 = call i64 @f2(%"a"* %ref.tmp) + ret i64 %call2 +} + +define internal i64 @f2(%"a"* %this) align 2 { +entry: + %this.addr = alloca %"a"*, align 8 + store %"a"* %this, %"a"** %this.addr, align 8 + %this1 = load %"a"*, %"a"** %this.addr, align 8 + %0 = bitcast %"a"* %this1 to %"b"* + call void @f3(%"b"* %0) + ret i64 undef +} + +define internal void @f3(%"b"* %this) align 2 { +entry: + %this.addr = alloca %"b"*, align 8 + store %"b"* %this, %"b"** %this.addr, align 8 + %this1 = load %"b"*, %"b"** %this.addr, align 8 + %call = call i1 @f4(%"b"* %this1) + ret void +} + +define internal i1 @f4(%"b"* %this) align 2 { +entry: + %this.addr = alloca %"b"*, align 8 + store %"b"* %this, %"b"** %this.addr, align 8 + %this1 = load %"b"*, %"b"** %this.addr, align 8 + %call = call %"a"* @f5(%"b"* %this1) + ret i1 undef +} + +define internal %"a"* @f5(%"b"* %this) align 2 { +entry: + %this.addr = alloca %"b"*, align 8 + store %"b"* %this, %"b"** %this.addr, align 8 + %this1 = load %"b"*, %"b"** %this.addr, align 8 + %0 = bitcast %"b"* %this1 to %"a"* + ret %"a"* %0 +} + +; CHECK: define hidden i64 @f1() +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i64 undef +; CHECK-NEXT: } + +; CHECK: define internal i64 @f2(%a* noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(8) %this) +; CHECK-NEXT: entry: +; CHECK-NEXT: %this.addr = alloca %a*, align 8 +; CHECK-NEXT: store %a* %this, %a** %this.addr, align 8 +; CHECK-NEXT: ret i64 undef +; CHECK-NEXT: } + +; CHECK: define internal void @f3(%b* noalias nocapture nofree readnone %this) +; CHECK-NEXT: entry: +; CHECK-NEXT: %this.addr = alloca %b*, align 8 +; CHECK-NEXT: store %b* %this, %b** %this.addr, align 8 +; CHECK-NEXT: ret void +; CHECK-NEXT: } + +; CHECK: define internal i1 @f4(%b* noalias nocapture nofree readnone %this) +; CHECK-NEXT: entry: +; CHECK-NEXT: %this.addr = alloca %b*, align 8 +; CHECK-NEXT: store %b* %this, %b** %this.addr, align 8 +; CHECK-NEXT: ret i1 undef +; CHECK-NEXT: } + +; CHECK: define internal noalias nonnull %a* @f5(%b* noalias nocapture nofree readnone %this) +; CHECK-NEXT: entry: +; CHECK-NEXT: %this.addr = alloca %b*, align 8 +; CHECK-NEXT: store %b* %this, %b** %this.addr, align 8 +; CHECK-NEXT: ret %a* undef +; CHECK-NEXT: } \ No newline at end of file diff --git a/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll b/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll --- a/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll +++ b/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll @@ -2,11 +2,14 @@ ; CHECK: Call graph node <><<{{.*}}>> #uses=0 ; CHECK: CS calls function 'dead_fork_call' -; CHECK: CS calls function 'd' +; CHECK: CS calls function '.omp_outlined..0' ; CHECK: CS calls function '__kmpc_fork_call' ; CHECK: CS calls function 'live_fork_call' ; CHECK: CS calls function '.omp_outlined..1' +; CHECK: CS calls function 'd' ; +; CHECK: Call graph node for function: '.omp_outlined..0'<<{{.*}}>> #uses=1 +; ; CHECK: Call graph node for function: '.omp_outlined..1'<<{{.*}}>> #uses=3 ; CHECK: CS<{{.*}}> calls function 'd' ;