Summary:
Several fixes to the handling of bitcode files without function summary
sections so that they are skipped during ThinLTO processing in llvm-lto
and the gold plugin when appropriate instead of aborting.
1 Don't assert when trying to add a FunctionInfo that doesn't have
a summary attached.
2 Skip FunctionInfo structures that don't have attached function summary
sections when trying to create the combined function summary.
3 In both llvm-lto and gold-plugin, check whether a bitcode file has
a function summary section before trying to parse the index, and skip
the bitcode file if it does not.
4 Fix hasFunctionSummaryInMemBuffer in BitcodeReader, which had a bug
where we returned to early while looking for the summary section.
Also added llvm-lto and gold-plugin based tests for cases where we
don't have function summaries in the bitcode file. I verified that
either the first couple fixes described above are enough to avoid the
crashes, or fixes 1,3,4. But have combined them all here for added
robustness.
Reviewers: joker.eph
Subscribers: llvm-commits, joker.eph
Differential Revision: http://reviews.llvm.org/D14903
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253796
91177308-0d34-0410-b5e6-
96231b3b80d8
/// Add a function info for a function of the given name.
void addFunctionInfo(StringRef FuncName, std::unique_ptr<FunctionInfo> Info) {
- if (ExportingModule) {
- assert(Info->functionSummary());
+ // Update the HasExportedFunctions flag, but only if we had a function
+ // summary (i.e. we aren't parsing them lazily or have a bitcode file
+ // without a function summary section).
+ if (ExportingModule && Info->functionSummary()) {
if (ExportingModule->getModuleIdentifier() ==
Info->functionSummary()->modulePath())
HasExportedFunctions = true;
case BitstreamEntry::SubBlock:
if (CheckFuncSummaryPresenceOnly) {
- if (Entry.ID == bitc::FUNCTION_SUMMARY_BLOCK_ID)
+ if (Entry.ID == bitc::FUNCTION_SUMMARY_BLOCK_ID) {
SeenFuncSummary = true;
+ // No need to parse the rest since we found the summary.
+ return std::error_code();
+ }
if (Stream.SkipBlock())
return error("Invalid record");
- // No need to parse the rest since we found the summary.
- return std::error_code();
+ continue;
}
switch (Entry.ID) {
default: // Skip unknown content.
assert(List.size() == 1);
std::unique_ptr<FunctionInfo> Info = std::move(List.front());
+ // Skip if there was no function summary section.
+ if (!Info->functionSummary())
+ continue;
+
// Add the module path string ref for this module if we haven't already
// saved a reference to it.
if (ModPath.empty())
+; First ensure that the ThinLTO handling in llvm-link and llvm-lto handles
+; bitcode without function summary sections gracefully.
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-as %p/Inputs/funcimport.ll -o %t2.bc
+; RUN: llvm-link %t.bc -functionindex=%t.bc -S
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+
; Do setup work for all below tests: generate bitcode and combined index
; RUN: llvm-as -function-summary %s -o %t.bc
; RUN: llvm-as -function-summary %p/Inputs/funcimport.ll -o %t2.bc
+; First ensure that the ThinLTO handling in the gold plugin handles
+; bitcode without function summary sections gracefully.
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/thinlto.ll -o %t2.o
+; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
+; RUN: --plugin-opt=thinlto \
+; RUN: -shared %t.o %t2.o -o %t3
+
; RUN: llvm-as -function-summary %s -o %t.o
; RUN: llvm-as -function-summary %p/Inputs/thinlto.ll -o %t2.o
MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize),
Info.name);
+
+ // Don't bother trying to build an index if there is no summary information
+ // in this bitcode file.
+ if (!object::FunctionIndexObjectFile::hasFunctionSummaryInMemBuffer(
+ BufferRef, diagnosticHandler))
+ return std::unique_ptr<FunctionInfoIndex>(nullptr);
+
ErrorOr<std::unique_ptr<object::FunctionIndexObjectFile>> ObjOrErr =
object::FunctionIndexObjectFile::create(BufferRef, diagnosticHandler);
std::unique_ptr<FunctionInfoIndex> Index =
getFunctionIndexForFile(F, File);
+
+ // Skip files without a function summary.
+ if (!Index)
+ continue;
+
CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
}
/// Parse the function index out of an IR file and return the function
/// index object if found, or nullptr if not.
-static std::unique_ptr<FunctionInfoIndex>
-getFunctionIndexForFile(StringRef Path, std::string &Error,
+static ErrorOr<std::unique_ptr<FunctionInfoIndex>>
+getFunctionIndexForFile(StringRef Path,
DiagnosticHandlerFunction DiagnosticHandler) {
std::unique_ptr<MemoryBuffer> Buffer;
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
MemoryBuffer::getFile(Path);
- if (std::error_code EC = BufferOrErr.getError()) {
- Error = EC.message();
- return nullptr;
- }
+ if (std::error_code EC = BufferOrErr.getError())
+ return EC;
Buffer = std::move(BufferOrErr.get());
+
+ // Don't bother trying to build an index if there is no summary information
+ // in this bitcode file.
+ if (!object::FunctionIndexObjectFile::hasFunctionSummaryInMemBuffer(
+ Buffer->getMemBufferRef(), DiagnosticHandler))
+ return std::unique_ptr<FunctionInfoIndex>(nullptr);
+
ErrorOr<std::unique_ptr<object::FunctionIndexObjectFile>> ObjOrErr =
object::FunctionIndexObjectFile::create(Buffer->getMemBufferRef(),
DiagnosticHandler);
- if (std::error_code EC = ObjOrErr.getError()) {
- Error = EC.message();
- return nullptr;
- }
+ if (std::error_code EC = ObjOrErr.getError())
+ return EC;
return (*ObjOrErr)->takeIndex();
}
FunctionInfoIndex CombinedIndex;
uint64_t NextModuleId = 0;
for (auto &Filename : InputFilenames) {
- std::string Error;
- std::unique_ptr<FunctionInfoIndex> Index =
- getFunctionIndexForFile(Filename, Error, diagnosticHandler);
- if (!Index) {
+ ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr =
+ getFunctionIndexForFile(Filename, diagnosticHandler);
+ if (std::error_code EC = IndexOrErr.getError()) {
+ std::string Error = EC.message();
errs() << Command << ": error loading file '" << Filename
<< "': " << Error << "\n";
return 1;
}
+ std::unique_ptr<FunctionInfoIndex> Index = std::move(IndexOrErr.get());
+ // Skip files without a function summary.
+ if (!Index)
+ continue;
CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
}
std::error_code EC;