diff --git a/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp b/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp --- a/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp +++ b/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp @@ -263,8 +263,15 @@ break; } + // Don't promote if the symbol is not defined in the module. This avoids + // creating a reference to a symbol that doesn't exist in the module + // This can happen when we compile with a sample profile collected from + // one binary but used for another, which may have profiled targets that + // aren't used in the new binary. We might have a declaration initially in + // the case where the symbol is globally dead in the binary and removed by + // ThinLTO. Function *TargetFunction = Symtab->getFunction(Target); - if (TargetFunction == nullptr) { + if (TargetFunction == nullptr || TargetFunction->isDeclaration()) { LLVM_DEBUG(dbgs() << " Not promote: Cannot find the target\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "UnableToFindTarget", &CB) diff --git a/llvm/test/LTO/Resolution/X86/load-sample-prof-icp.ll b/llvm/test/LTO/Resolution/X86/load-sample-prof-icp.ll --- a/llvm/test/LTO/Resolution/X86/load-sample-prof-icp.ll +++ b/llvm/test/LTO/Resolution/X86/load-sample-prof-icp.ll @@ -3,11 +3,11 @@ ; ; RUN: opt -module-summary < %s -o %t.bc ; RUN: llvm-lto2 run -o %t.out %t.bc -save-temps \ -; RUN: -r %t.bc,test,px -r %t.bc,bar,x \ +; RUN: -r %t.bc,test,px -r %t.bc,bar,px -r %t.bc,externfunc,x \ ; RUN: -lto-sample-profile-file=%S/Inputs/load-sample-prof-icp.prof ; RUN: llvm-dis %t.out.1.4.opt.bc -o - | FileCheck %s ; RUN: llvm-lto2 run -o %t.out %t.bc -save-temps \ -; RUN: -r %t.bc,test,px -r %t.bc,bar,x -use-new-pm \ +; RUN: -r %t.bc,test,px -r %t.bc,bar,px -r %t.bc,externfunc,x -use-new-pm \ ; RUN: -lto-sample-profile-file=%S/Inputs/load-sample-prof-icp.prof ; RUN: llvm-dis %t.out.1.4.opt.bc -o - | FileCheck %s @@ -26,9 +26,14 @@ ret void } -declare void @bar() local_unnamed_addr +declare void @externfunc() -attributes #0 = {"use-sample-profile"} +define void @bar() #0 { + call void @externfunc() + ret void +} + +attributes #0 = {"use-sample-profile" noinline} !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5} diff --git a/llvm/test/Transforms/PGOProfile/icp_covariant_call_return.ll b/llvm/test/Transforms/PGOProfile/icp_covariant_call_return.ll --- a/llvm/test/Transforms/PGOProfile/icp_covariant_call_return.ll +++ b/llvm/test/Transforms/PGOProfile/icp_covariant_call_return.ll @@ -10,7 +10,9 @@ declare noalias i8* @_Znwm(i64) declare void @_ZN1DC2Ev(%struct.D*); -declare %struct.Derived* @_ZN1D4funcEv(%struct.D*); +define %struct.Derived* @_ZN1D4funcEv(%struct.D*) { + ret %struct.Derived* null +} define %struct.Base* @bar() { entry: diff --git a/llvm/test/Transforms/PGOProfile/icp_covariant_invoke_return.ll b/llvm/test/Transforms/PGOProfile/icp_covariant_invoke_return.ll --- a/llvm/test/Transforms/PGOProfile/icp_covariant_invoke_return.ll +++ b/llvm/test/Transforms/PGOProfile/icp_covariant_invoke_return.ll @@ -10,7 +10,9 @@ @_ZTIi = external constant i8* declare i8* @_Znwm(i64) declare void @_ZN1DC2Ev(%struct.D*) -declare %struct.Derived* @_ZN1D4funcEv(%struct.D*) +define %struct.Derived* @_ZN1D4funcEv(%struct.D*) { + ret %struct.Derived* null +} declare void @_ZN1DD0Ev(%struct.D*) declare void @_ZdlPv(i8*) declare i32 @__gxx_personality_v0(...) diff --git a/llvm/test/Transforms/PGOProfile/indirect_call_promotion_musttail.ll b/llvm/test/Transforms/PGOProfile/indirect_call_promotion_musttail.ll --- a/llvm/test/Transforms/PGOProfile/indirect_call_promotion_musttail.ll +++ b/llvm/test/Transforms/PGOProfile/indirect_call_promotion_musttail.ll @@ -6,13 +6,21 @@ @foo = common global i32* ()* null, align 8 -declare i32* @func1() +define i32* @func1() { + ret i32* null +} -declare i32* @func2() +define i32* @func2() { + ret i32* null +} -declare i32* @func3() +define i32* @func3() { + ret i32* null +} -declare i32* @func4() +define i32* @func4() { + ret i32* null +} define i32* @bar() { entry: