Index: llvm/include/llvm/LTO/LTOBackend.h =================================================================== --- llvm/include/llvm/LTO/LTOBackend.h +++ llvm/include/llvm/LTO/LTOBackend.h @@ -45,6 +45,9 @@ const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector &ModuleMap); + +Error finalizeOptimizationRemarks( + std::unique_ptr DiagOutputFile); } } Index: llvm/lib/IR/DiagnosticInfo.cpp =================================================================== --- llvm/lib/IR/DiagnosticInfo.cpp +++ llvm/lib/IR/DiagnosticInfo.cpp @@ -243,11 +243,8 @@ RemarkName, *Inst->getParent()->getParent(), Inst->getDebugLoc(), Inst->getParent()) {} -// Helper to allow for an assert before attempting to return an invalid -// reference. -static const BasicBlock &getFirstFunctionBlock(const Function *Func) { - assert(!Func->empty() && "Function does not have a body"); - return Func->front(); +static const BasicBlock *getFirstFunctionBlock(const Function *Func) { + return Func->empty() ? nullptr : &Func->front(); } OptimizationRemark::OptimizationRemark(const char *PassName, @@ -255,7 +252,7 @@ const Function *Func) : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName, RemarkName, *Func, Func->getSubprogram(), - &getFirstFunctionBlock(Func)) {} + getFirstFunctionBlock(Func)) {} bool OptimizationRemark::isEnabled() const { const Function &Fn = getFunction(); Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -12,6 +12,7 @@ #include "llvm/LTO/LTO.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeReader.h" @@ -31,6 +32,7 @@ #include "llvm/Object/IRObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -781,8 +783,16 @@ bool LivenessFromIndex) { std::vector Keep; for (GlobalValue *GV : Mod.Keep) { - if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) + if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) { + if (Function *F = dyn_cast(GV)) { + OptimizationRemarkEmitter ORE(F); + auto RemStr = + formatv("Function not added to combined module: {0}", F->getName()); + ORE.emit(OptimizationRemark(DEBUG_TYPE, "deadfunction", F) + << RemStr.str()); + } continue; + } if (!GV->hasAvailableExternallyLinkage()) { Keep.push_back(GV); @@ -931,17 +941,6 @@ return StatsFileOrErr.takeError(); std::unique_ptr StatsFile = std::move(StatsFileOrErr.get()); - // Finalize linking of regular LTO modules containing summaries now that - // we have computed liveness information. - for (auto &M : RegularLTO.ModsWithSummaries) - if (Error Err = linkRegularLTO(std::move(M), - /*LivenessFromIndex=*/true)) - return Err; - - // Ensure we don't have inconsistently split LTO units with type tests. - if (Error Err = checkPartiallySplit()) - return Err; - Error Result = runRegularLTO(AddStream); if (!Result) Result = runThinLTO(AddStream, Cache, GUIDPreservedSymbols); @@ -953,6 +952,24 @@ } Error LTO::runRegularLTO(AddStreamFn AddStream) { + // Setup optimization remarks. + auto DiagFileOrErr = lto::setupOptimizationRemarks( + RegularLTO.CombinedModule->getContext(), Conf.RemarksFilename, + Conf.RemarksPasses, Conf.RemarksFormat, Conf.RemarksWithHotness); + if (!DiagFileOrErr) + return DiagFileOrErr.takeError(); + + // Finalize linking of regular LTO modules containing summaries now that + // we have computed liveness information. + for (auto &M : RegularLTO.ModsWithSummaries) + if (Error Err = linkRegularLTO(std::move(M), + /*LivenessFromIndex=*/true)) + return Err; + + // Ensure we don't have inconsistently split LTO units with type tests. + if (Error Err = checkPartiallySplit()) + return Err; + // Make sure commons have the right size/alignment: we kept the largest from // all the prevailing when adding the inputs, and we apply it here. const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout(); @@ -1017,8 +1034,12 @@ !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule)) return Error::success(); } - return backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel, - std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex); + if (Error Err = + backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel, + std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex)) + return Err; + + return finalizeOptimizationRemarks(std::move(*DiagFileOrErr)); } static const char *libcallRoutineNames[] = { Index: llvm/lib/LTO/LTOBackend.cpp =================================================================== --- llvm/lib/LTO/LTOBackend.cpp +++ llvm/lib/LTO/LTOBackend.cpp @@ -434,8 +434,8 @@ } } -static Error -finalizeOptimizationRemarks(std::unique_ptr DiagOutputFile) { +Error lto::finalizeOptimizationRemarks( + std::unique_ptr DiagOutputFile) { // Make sure we flush the diagnostic remarks file in case the linker doesn't // call the global destructors before exiting. if (!DiagOutputFile) @@ -455,18 +455,10 @@ std::unique_ptr TM = createTargetMachine(C, *TOrErr, *Mod); - // Setup optimization remarks. - auto DiagFileOrErr = lto::setupOptimizationRemarks( - Mod->getContext(), C.RemarksFilename, C.RemarksPasses, C.RemarksFormat, - C.RemarksWithHotness); - if (!DiagFileOrErr) - return DiagFileOrErr.takeError(); - auto DiagnosticOutputFile = std::move(*DiagFileOrErr); - if (!C.CodeGenOnly) { if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false, /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr)) - return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); + return Error::success(); } if (ParallelCodeGenParallelismLevel == 1) { @@ -475,7 +467,7 @@ splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel, std::move(Mod)); } - return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); + return Error::success(); } static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals, Index: llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll =================================================================== --- llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll +++ llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll @@ -1,18 +1,23 @@ ; RUN: opt -module-summary -o %t %s ; RUN: opt -module-summary -o %t2 %S/Inputs/dead-strip-fulllto.ll -; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1, -r %t,live2,p -r %t,dead2,p \ +; RUN: llvm-lto2 run --pass-remarks-output=%t4.yaml --pass-remarks-filter=. \ +; RUN: %t -r %t,main,px -r %t,live1, -r %t,live2,p -r %t,dead2,p \ ; RUN: %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, -r %t2,odr, \ -; RUN: -save-temps -o %t3 +; RUN: -save-temps -o %t3 + +; RUN: cat %t4.yaml | FileCheck %s -check-prefix=REMARK ; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s ; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s ; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1, -r %t,live2,p -r %t,dead2,p \ ; RUN: %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, -r %t2,odr, \ -; RUN: -save-temps -o %t3 -O0 +; RUN: -save-temps -o %t3 -O0 ; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s ; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s +; REMARK: 'Function not added to combined module: dead2' + ; FULL-NOT: dead ; FULL: U live1 ; FULL: T live2