diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -87,6 +87,7 @@ inputSections.clear(); outputSections.clear(); + memoryBuffers.clear(); archiveFiles.clear(); binaryFiles.clear(); bitcodeFiles.clear(); @@ -1987,6 +1988,23 @@ return symtab->addSymbol(sym); } +// MemoryBuffers backing BitcodeFiles are unused from now on. Mark input files +// as MADV_DONTNEED so that these pages can be reused by the expensive thin +// link, saving memory. +// +// With --thinlto-index-only, for ELFFileBase files, their MemoryBuffers are +// nearly unused as well, but the saving is typically small because +// in LTO links bitcode files typically dominate. +static void markBuffersAsDontNeed() { + DenseSet bufs; + for (BitcodeFile *file : elf::bitcodeFiles) + bufs.insert(file->mb.getBufferStart()); + + for (MemoryBuffer &mb : llvm::make_pointee_range(memoryBuffers)) + if (bufs.count(mb.getBufferStart())) + mb.dontNeedIfMmap(); +} + // This function is where all the optimizations of link-time // optimization takes place. When LTO is in use, some input files are // not in native object file format but in the LLVM bitcode format. @@ -2001,6 +2019,9 @@ for (BitcodeFile *file : bitcodeFiles) lto->add(*file); + if (!bitcodeFiles.empty()) + markBuffersAsDontNeed(); + for (InputFile *file : lto->compile()) { auto *obj = cast>(file); obj->parse(/*ignoreComdats=*/true); diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -407,6 +407,7 @@ std::string replaceThinLTOSuffix(StringRef path); +extern SmallVector> memoryBuffers; extern SmallVector archiveFiles; extern SmallVector binaryFiles; extern SmallVector bitcodeFiles; diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -43,6 +43,7 @@ bool InputFile::isInGroup; uint32_t InputFile::nextGroupId; +SmallVector> elf::memoryBuffers; SmallVector elf::archiveFiles; SmallVector elf::binaryFiles; SmallVector elf::bitcodeFiles; @@ -122,9 +123,8 @@ return None; } - std::unique_ptr &mb = *mbOrErr; - MemoryBufferRef mbref = mb->getMemBufferRef(); - make>(std::move(mb)); // take MB ownership + MemoryBufferRef mbref = (*mbOrErr)->getMemBufferRef(); + memoryBuffers.push_back(std::move(*mbOrErr)); // take MB ownership if (tar) tar->append(relativeToRoot(path), mbref.getBuffer());