diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h --- a/llvm/include/llvm/IR/GlobalValue.h +++ b/llvm/include/llvm/IR/GlobalValue.h @@ -145,12 +145,20 @@ case AppendingLinkage: case InternalLinkage: case PrivateLinkage: - return isInterposable(); + // Optimizations may assume builtin semantics for functions defined as + // nobuiltin due to attributes at call-sites. To avoid applying IPO based + // on nobuiltin semantics, treat such function definitions as maybe + // derefined. + return isInterposable() || isNobuiltinFnDef(); } llvm_unreachable("Fully covered switch above!"); } + /// Returns true if the global is a function definition with the nobuiltin + /// attribute. + bool isNobuiltinFnDef() const; + protected: /// The intrinsic ID for this subclass (which must be a Function). /// diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -261,6 +261,13 @@ setGlobalObjectFlag(HasSectionHashEntryBit, !S.empty()); } +bool GlobalValue::isNobuiltinFnDef() const { + const Function *F = dyn_cast(this); + if (!F || F->empty()) + return false; + return F->hasFnAttribute(Attribute::NoBuiltin); +} + bool GlobalValue::isDeclaration() const { // Globals are definitions if they have an initializer. if (const GlobalVariable *GV = dyn_cast(this)) diff --git a/llvm/test/Transforms/DeadArgElim/pr49022-builtin-nobuiltin.ll b/llvm/test/Transforms/DeadArgElim/pr49022-builtin-nobuiltin.ll --- a/llvm/test/Transforms/DeadArgElim/pr49022-builtin-nobuiltin.ll +++ b/llvm/test/Transforms/DeadArgElim/pr49022-builtin-nobuiltin.ll @@ -13,7 +13,7 @@ define dso_local i32 @test_fn(ptr %ptr) { ; CHECK-LABEL: @test_fn( ; CHECK-NEXT: entry: -; CHECK-NEXT: call void @_ZdlPv(ptr poison) #[[ATTR1:[0-9]+]] +; CHECK-NEXT: call void @_ZdlPv(ptr [[PTR:%.*]]) #[[ATTR1:[0-9]+]] ; CHECK-NEXT: ret i32 1 ; entry: