diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -34,7 +34,7 @@ void createFiles(llvm::opt::InputArgList &args); void inferMachineType(); template void link(llvm::opt::InputArgList &args); - template void compileBitcodeFiles(); + template void compileBitcodeFiles(bool skipLinkedOutput); // True if we are in --whole-archive and --no-whole-archive. bool inWholeArchive = false; 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,28 @@ return symtab->addSymbol(sym); } +static void markBuffersAsDontNeed(bool skipLinkedOutput) { + // With --thinlto-index-only, all buffers are nearly unused from now on + // (except symbol/section names used by infrequent passes). Mark input file + // buffers as MADV_DONTNEED so that these pages can be reused by the expensive + // thin link, saving memory. + if (skipLinkedOutput) { + for (MemoryBuffer &mb : llvm::make_pointee_range(memoryBuffers)) + mb.dontNeedIfMmap(); + return; + } + + // Otherwise, just mark MemoryBuffers backing BitcodeFiles. + DenseSet bufs; + for (BitcodeFile *file : bitcodeFiles) + bufs.insert(file->mb.getBufferStart()); + for (BitcodeFile *file : lazyBitcodeFiles) + 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. @@ -1994,13 +2017,17 @@ // using LLVM functions and replaces bitcode symbols with the results. // Because all bitcode files that the program consists of are passed to // the compiler at once, it can do a whole-program optimization. -template void LinkerDriver::compileBitcodeFiles() { +template +void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) { llvm::TimeTraceScope timeScope("LTO"); // Compile bitcode files and replace bitcode symbols. lto.reset(new BitcodeCompiler); for (BitcodeFile *file : bitcodeFiles) lto->add(*file); + if (!bitcodeFiles.empty()) + markBuffersAsDontNeed(skipLinkedOutput); + for (InputFile *file : lto->compile()) { auto *obj = cast>(file); obj->parse(/*ignoreComdats=*/true); @@ -2364,28 +2391,31 @@ symtab->scanVersionScript(); } + // Skip the normal linked output if some LTO options are specified. + // + // For --thinlto-index-only, index file creation is performed in + // compileBitcodeFiles, so we are done afterwards. --plugin-opt=emit-llvm and + // --plugin-opt=emit-asm create output files in bitcode or assembly code, + // respectively. When only certain thinLTO modules are specified for + // compilation, the intermediate object file are the expected output. + const bool skipLinkedOutput = config->thinLTOIndexOnly || config->emitLLVM || + config->ltoEmitAsm || + !config->thinLTOModulesToCompile.empty(); + // Do link-time optimization if given files are LLVM bitcode files. // This compiles bitcode files into real object files. // // With this the symbol table should be complete. After this, no new names // except a few linker-synthesized ones will be added to the symbol table. - compileBitcodeFiles(); + compileBitcodeFiles(skipLinkedOutput); // Symbol resolution finished. Report backward reference problems. reportBackrefs(); if (errorCount()) return; - // If --thinlto-index-only is given, we should create only "index - // files" and not object files. Index file creation is already done - // in compileBitcodeFiles, so we are done if that's the case. - // Likewise, --plugin-opt=emit-llvm and --plugin-opt=emit-asm are the - // options to create output files in bitcode or assembly code - // respectively. No object files are generated. - // Also bail out here when only certain thinLTO modules are specified for - // compilation. The intermediate object file are the expected output. - if (config->thinLTOIndexOnly || config->emitLLVM || config->ltoEmitAsm || - !config->thinLTOModulesToCompile.empty()) + // Bail out if normal linked output is skipped due to LTO. + if (skipLinkedOutput) return; // Handle --exclude-libs again because lto.tmp may reference additional 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());