diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /lib/LTO | |
parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) |
Notes
Diffstat (limited to 'lib/LTO')
-rw-r--r-- | lib/LTO/CMakeLists.txt | 51 | ||||
-rw-r--r-- | lib/LTO/Caching.cpp | 82 | ||||
-rw-r--r-- | lib/LTO/LTO.cpp | 424 | ||||
-rw-r--r-- | lib/LTO/LTOBackend.cpp | 117 | ||||
-rw-r--r-- | lib/LTO/LTOCodeGenerator.cpp | 32 | ||||
-rw-r--r-- | lib/LTO/LTOModule.cpp | 11 | ||||
-rw-r--r-- | lib/LTO/ThinLTOCodeGenerator.cpp | 59 | ||||
-rw-r--r-- | lib/LTO/UpdateCompilerUsed.cpp | 2 |
8 files changed, 462 insertions, 316 deletions
diff --git a/lib/LTO/CMakeLists.txt b/lib/LTO/CMakeLists.txt index c73143eb330be..73b5662d4bc8e 100644 --- a/lib/LTO/CMakeLists.txt +++ b/lib/LTO/CMakeLists.txt @@ -1,52 +1,3 @@ -# Figure out if we can track VC revisions. -function(find_first_existing_file out_var) - foreach(file ${ARGN}) - if(EXISTS "${file}") - set(${out_var} "${file}" PARENT_SCOPE) - return() - endif() - endforeach() -endfunction() - -macro(find_first_existing_vc_file out_var path) - find_first_existing_file(${out_var} - "${path}/.git/logs/HEAD" # Git - "${path}/.svn/wc.db" # SVN 1.7 - "${path}/.svn/entries" # SVN 1.6 - ) -endmacro() - -find_first_existing_vc_file(llvm_vc "${LLVM_MAIN_SRC_DIR}") - -# The VC revision include that we want to generate. -set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/LLVMLTORevision.h") - -set(get_svn_script "${LLVM_CMAKE_PATH}/GenerateVersionFromCVS.cmake") - -if(DEFINED llvm_vc) - # Create custom target to generate the VC revision include. - add_custom_command(OUTPUT "${version_inc}" - DEPENDS "${llvm_vc}" "${get_svn_script}" - COMMAND - ${CMAKE_COMMAND} "-DSOURCE_DIR=${LLVM_MAIN_SRC_DIR}" - "-DNAME=LLVM_REVISION" - "-DHEADER_FILE=${version_inc}" - -P "${get_svn_script}") - - # Mark the generated header as being generated. - set_source_files_properties("${version_inc}" - PROPERTIES GENERATED TRUE - HEADER_FILE_ONLY TRUE) - - # Tell Version.cpp that it needs to build with -DHAVE_SVN_VERSION_INC. - set_source_files_properties(Version.cpp - PROPERTIES COMPILE_DEFINITIONS "HAVE_SVN_VERSION_INC") -else() - # Not producing a VC revision include. - set(version_inc) -endif() - - add_llvm_library(LLVMLTO Caching.cpp LTO.cpp @@ -55,11 +6,11 @@ add_llvm_library(LLVMLTO LTOCodeGenerator.cpp UpdateCompilerUsed.cpp ThinLTOCodeGenerator.cpp - ${version_inc} ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/LTO DEPENDS intrinsics_gen + llvm_vcsrevision_h ) diff --git a/lib/LTO/Caching.cpp b/lib/LTO/Caching.cpp index fd5bdb0bc01a1..e32e46c4c3c8d 100644 --- a/lib/LTO/Caching.cpp +++ b/lib/LTO/Caching.cpp @@ -13,6 +13,7 @@ #include "llvm/LTO/Caching.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -21,70 +22,71 @@ using namespace llvm; using namespace llvm::lto; -static void commitEntry(StringRef TempFilename, StringRef EntryPath) { - // Rename to final destination (hopefully race condition won't matter here) - auto EC = sys::fs::rename(TempFilename, EntryPath); - if (EC) { - // Renaming failed, probably not the same filesystem, copy and delete. - // FIXME: Avoid needing to do this by creating the temporary file in the - // cache directory. - { - auto ReloadedBufferOrErr = MemoryBuffer::getFile(TempFilename); - if (auto EC = ReloadedBufferOrErr.getError()) - report_fatal_error(Twine("Failed to open temp file '") + TempFilename + - "': " + EC.message() + "\n"); +Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath, + AddBufferFn AddBuffer) { + if (std::error_code EC = sys::fs::create_directories(CacheDirectoryPath)) + return errorCodeToError(EC); - raw_fd_ostream OS(EntryPath, EC, sys::fs::F_None); - if (EC) - report_fatal_error(Twine("Failed to open ") + EntryPath + - " to save cached entry\n"); - // I'm not sure what are the guarantee if two processes are doing this - // at the same time. - OS << (*ReloadedBufferOrErr)->getBuffer(); - } - sys::fs::remove(TempFilename); - } -} - -NativeObjectCache lto::localCache(std::string CacheDirectoryPath, - AddFileFn AddFile) { return [=](unsigned Task, StringRef Key) -> AddStreamFn { - // First, see if we have a cache hit. + // This choice of file name allows the cache to be pruned (see pruneCache() + // in include/llvm/Support/CachePruning.h). SmallString<64> EntryPath; - sys::path::append(EntryPath, CacheDirectoryPath, Key); - if (sys::fs::exists(EntryPath)) { - AddFile(Task, EntryPath); + sys::path::append(EntryPath, CacheDirectoryPath, "llvmcache-" + Key); + // First, see if we have a cache hit. + ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = + MemoryBuffer::getFile(EntryPath); + if (MBOrErr) { + AddBuffer(Task, std::move(*MBOrErr)); return AddStreamFn(); } + if (MBOrErr.getError() != errc::no_such_file_or_directory) + report_fatal_error(Twine("Failed to open cache file ") + EntryPath + + ": " + MBOrErr.getError().message() + "\n"); + // This native object stream is responsible for commiting the resulting - // file to the cache and calling AddFile to add it to the link. + // file to the cache and calling AddBuffer to add it to the link. struct CacheStream : NativeObjectStream { - AddFileFn AddFile; + AddBufferFn AddBuffer; std::string TempFilename; std::string EntryPath; unsigned Task; - CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddFileFn AddFile, + CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddBufferFn AddBuffer, std::string TempFilename, std::string EntryPath, unsigned Task) - : NativeObjectStream(std::move(OS)), AddFile(AddFile), - TempFilename(TempFilename), EntryPath(EntryPath), Task(Task) {} + : NativeObjectStream(std::move(OS)), AddBuffer(std::move(AddBuffer)), + TempFilename(std::move(TempFilename)), + EntryPath(std::move(EntryPath)), Task(Task) {} ~CacheStream() { + // FIXME: This code could race with the cache pruner, but it is unlikely + // that the cache pruner will choose to remove a newly created file. + // Make sure the file is closed before committing it. OS.reset(); - commitEntry(TempFilename, EntryPath); - AddFile(Task, EntryPath); + // This is atomic on POSIX systems. + if (auto EC = sys::fs::rename(TempFilename, EntryPath)) + report_fatal_error(Twine("Failed to rename temporary file ") + + TempFilename + ": " + EC.message() + "\n"); + + ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = + MemoryBuffer::getFile(EntryPath); + if (!MBOrErr) + report_fatal_error(Twine("Failed to open cache file ") + EntryPath + + ": " + MBOrErr.getError().message() + "\n"); + AddBuffer(Task, std::move(*MBOrErr)); } }; return [=](size_t Task) -> std::unique_ptr<NativeObjectStream> { // Write to a temporary to avoid race condition int TempFD; - SmallString<64> TempFilename; + SmallString<64> TempFilenameModel, TempFilename; + sys::path::append(TempFilenameModel, CacheDirectoryPath, "Thin-%%%%%%.tmp.o"); std::error_code EC = - sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename); + sys::fs::createUniqueFile(TempFilenameModel, TempFD, TempFilename, + sys::fs::owner_read | sys::fs::owner_write); if (EC) { errs() << "Error: " << EC.message() << "\n"; report_fatal_error("ThinLTO: Can't get a temporary file"); @@ -93,7 +95,7 @@ NativeObjectCache lto::localCache(std::string CacheDirectoryPath, // This CacheStream will move the temporary file into the cache when done. return llvm::make_unique<CacheStream>( llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true), - AddFile, TempFilename.str(), EntryPath.str(), Task); + AddBuffer, TempFilename.str(), EntryPath.str(), Task); }; }; } diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index e3e2f9f806c88..9782c898bf503 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -20,9 +20,13 @@ #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Metadata.h" #include "llvm/LTO/LTOBackend.h" #include "llvm/Linker/IRMover.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/ModuleSummaryIndexObjectFile.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -31,6 +35,7 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/VCSRevision.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -46,6 +51,12 @@ using namespace object; #define DEBUG_TYPE "lto" +// The values are (type identifier, summary) pairs. +typedef DenseMap< + GlobalValue::GUID, + TinyPtrVector<const std::pair<const std::string, TypeIdSummary> *>> + TypeIdSummariesByGuidTy; + // Returns a unique hash for the Module considering the current list of // export/import and other global analysis results. // The hash is produced in \p Key. @@ -54,7 +65,8 @@ static void computeCacheKey( StringRef ModuleID, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - const GVSummaryMapTy &DefinedGlobals) { + const GVSummaryMapTy &DefinedGlobals, + const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) { // Compute the unique hash for this entry. // This is based on the current compiler version, the module itself, the // export list, the hash for every single module in the import list, the @@ -63,7 +75,7 @@ static void computeCacheKey( // Start with the compiler revision Hasher.update(LLVM_VERSION_STRING); -#ifdef HAVE_LLVM_REVISION +#ifdef LLVM_REVISION Hasher.update(LLVM_REVISION); #endif @@ -80,6 +92,18 @@ static void computeCacheKey( Data[3] = I >> 24; Hasher.update(ArrayRef<uint8_t>{Data, 4}); }; + auto AddUint64 = [&](uint64_t I) { + uint8_t Data[8]; + Data[0] = I; + Data[1] = I >> 8; + Data[2] = I >> 16; + Data[3] = I >> 24; + Data[4] = I >> 32; + Data[5] = I >> 40; + Data[6] = I >> 48; + Data[7] = I >> 56; + Hasher.update(ArrayRef<uint8_t>{Data, 8}); + }; AddString(Conf.CPU); // FIXME: Hash more of Options. For now all clients initialize Options from // command-line flags (which is unsupported in production), but may set @@ -94,6 +118,7 @@ static void computeCacheKey( AddUnsigned(Conf.RelocModel); AddUnsigned(Conf.CodeModel); AddUnsigned(Conf.CGOptLevel); + AddUnsigned(Conf.CGFileType); AddUnsigned(Conf.OptLevel); AddString(Conf.OptPipeline); AddString(Conf.AAPipeline); @@ -107,10 +132,16 @@ static void computeCacheKey( // The export list can impact the internalization, be conservative here Hasher.update(ArrayRef<uint8_t>((uint8_t *)&F, sizeof(F))); - // Include the hash for every module we import functions from + // Include the hash for every module we import functions from. The set of + // imported symbols for each module may affect code generation and is + // sensitive to link order, so include that as well. for (auto &Entry : ImportList) { auto ModHash = Index.getModuleHash(Entry.first()); Hasher.update(ArrayRef<uint8_t>((uint8_t *)&ModHash[0], sizeof(ModHash))); + + AddUint64(Entry.second.size()); + for (auto &Fn : Entry.second) + AddUint64(Fn.first); } // Include the hash for the resolved ODR. @@ -121,12 +152,68 @@ static void computeCacheKey( sizeof(GlobalValue::LinkageTypes))); } + std::set<GlobalValue::GUID> UsedTypeIds; + + auto AddUsedTypeIds = [&](GlobalValueSummary *GS) { + auto *FS = dyn_cast_or_null<FunctionSummary>(GS); + if (!FS) + return; + for (auto &TT : FS->type_tests()) + UsedTypeIds.insert(TT); + for (auto &TT : FS->type_test_assume_vcalls()) + UsedTypeIds.insert(TT.GUID); + for (auto &TT : FS->type_checked_load_vcalls()) + UsedTypeIds.insert(TT.GUID); + for (auto &TT : FS->type_test_assume_const_vcalls()) + UsedTypeIds.insert(TT.VFunc.GUID); + for (auto &TT : FS->type_checked_load_const_vcalls()) + UsedTypeIds.insert(TT.VFunc.GUID); + }; + // Include the hash for the linkage type to reflect internalization and weak - // resolution. + // resolution, and collect any used type identifier resolutions. for (auto &GS : DefinedGlobals) { GlobalValue::LinkageTypes Linkage = GS.second->linkage(); Hasher.update( ArrayRef<uint8_t>((const uint8_t *)&Linkage, sizeof(Linkage))); + AddUsedTypeIds(GS.second); + } + + // Imported functions may introduce new uses of type identifier resolutions, + // so we need to collect their used resolutions as well. + for (auto &ImpM : ImportList) + for (auto &ImpF : ImpM.second) + AddUsedTypeIds(Index.findSummaryInModule(ImpF.first, ImpM.first())); + + auto AddTypeIdSummary = [&](StringRef TId, const TypeIdSummary &S) { + AddString(TId); + + AddUnsigned(S.TTRes.TheKind); + AddUnsigned(S.TTRes.SizeM1BitWidth); + + AddUint64(S.WPDRes.size()); + for (auto &WPD : S.WPDRes) { + AddUnsigned(WPD.first); + AddUnsigned(WPD.second.TheKind); + AddString(WPD.second.SingleImplName); + + AddUint64(WPD.second.ResByArg.size()); + for (auto &ByArg : WPD.second.ResByArg) { + AddUint64(ByArg.first.size()); + for (uint64_t Arg : ByArg.first) + AddUint64(Arg); + AddUnsigned(ByArg.second.TheKind); + AddUint64(ByArg.second.Info); + } + } + }; + + // Include the hash for all type identifiers used by this module. + for (GlobalValue::GUID TId : UsedTypeIds) { + auto SummariesI = TypeIdSummariesByGuid.find(TId); + if (SummariesI != TypeIdSummariesByGuid.end()) + for (auto *Summary : SummariesI->second) + AddTypeIdSummary(Summary->first, Summary->second); } if (!Conf.SampleProfile.empty()) { @@ -164,9 +251,7 @@ static void thinLTOResolveWeakForLinkerGUID( } // Alias and aliasee can't be turned into available_externally. else if (!isa<AliasSummary>(S.get()) && - !GlobalInvolvedWithAlias.count(S.get()) && - (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage) || - GlobalValue::isWeakODRLinkage(OriginalLinkage))) + !GlobalInvolvedWithAlias.count(S.get())) S->setLinkage(GlobalValue::AvailableExternallyLinkage); if (S->linkage() != OriginalLinkage) recordNewLinkage(S->modulePath(), GUID, S->linkage()); @@ -220,14 +305,6 @@ void llvm::thinLTOInternalizeAndPromoteInIndex( thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported); } -struct InputFile::InputModule { - BitcodeModule BM; - std::unique_ptr<Module> Mod; - - // The range of ModuleSymbolTable entries for this input module. - size_t SymBegin, SymEnd; -}; - // Requires a destructor for std::vector<InputModule>. InputFile::~InputFile() = default; @@ -248,61 +325,52 @@ Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) { return make_error<StringError>("Bitcode file does not contain any modules", inconvertibleErrorCode()); - // Create an InputModule for each module in the InputFile, and add it to the - // ModuleSymbolTable. + File->Mods = *BMsOrErr; + + LLVMContext Ctx; + std::vector<Module *> Mods; + std::vector<std::unique_ptr<Module>> OwnedMods; for (auto BM : *BMsOrErr) { Expected<std::unique_ptr<Module>> MOrErr = - BM.getLazyModule(File->Ctx, /*ShouldLazyLoadMetadata*/ true, + BM.getLazyModule(Ctx, /*ShouldLazyLoadMetadata*/ true, /*IsImporting*/ false); if (!MOrErr) return MOrErr.takeError(); - size_t SymBegin = File->SymTab.symbols().size(); - File->SymTab.addModule(MOrErr->get()); - size_t SymEnd = File->SymTab.symbols().size(); + if ((*MOrErr)->getDataLayoutStr().empty()) + return make_error<StringError>("input module has no datalayout", + inconvertibleErrorCode()); - for (const auto &C : (*MOrErr)->getComdatSymbolTable()) { - auto P = File->ComdatMap.insert( - std::make_pair(&C.second, File->Comdats.size())); - assert(P.second); - (void)P; - File->Comdats.push_back(C.first()); - } + Mods.push_back(MOrErr->get()); + OwnedMods.push_back(std::move(*MOrErr)); + } - File->Mods.push_back({BM, std::move(*MOrErr), SymBegin, SymEnd}); + SmallVector<char, 0> Symtab; + if (Error E = irsymtab::build(Mods, Symtab, File->Strtab)) + return std::move(E); + + irsymtab::Reader R({Symtab.data(), Symtab.size()}, + {File->Strtab.data(), File->Strtab.size()}); + File->TargetTriple = R.getTargetTriple(); + File->SourceFileName = R.getSourceFileName(); + File->COFFLinkerOpts = R.getCOFFLinkerOpts(); + File->ComdatTable = R.getComdatTable(); + + for (unsigned I = 0; I != Mods.size(); ++I) { + size_t Begin = File->Symbols.size(); + for (const irsymtab::Reader::SymbolRef &Sym : R.module_symbols(I)) + // Skip symbols that are irrelevant to LTO. Note that this condition needs + // to match the one in Skip() in LTO::addRegularLTO(). + if (Sym.isGlobal() && !Sym.isFormatSpecific()) + File->Symbols.push_back(Sym); + File->ModuleSymIndices.push_back({Begin, File->Symbols.size()}); } return std::move(File); } -Expected<int> InputFile::Symbol::getComdatIndex() const { - if (!isGV()) - return -1; - const GlobalObject *GO = getGV()->getBaseObject(); - if (!GO) - return make_error<StringError>("Unable to determine comdat of alias!", - inconvertibleErrorCode()); - if (const Comdat *C = GO->getComdat()) { - auto I = File->ComdatMap.find(C); - assert(I != File->ComdatMap.end()); - return I->second; - } - return -1; -} - StringRef InputFile::getName() const { - return Mods[0].BM.getModuleIdentifier(); -} - -StringRef InputFile::getSourceFileName() const { - return Mods[0].Mod->getSourceFileName(); -} - -iterator_range<InputFile::symbol_iterator> -InputFile::module_symbols(InputModule &IM) { - return llvm::make_range( - symbol_iterator(SymTab.symbols().data() + IM.SymBegin, SymTab, this), - symbol_iterator(SymTab.symbols().data() + IM.SymEnd, SymTab, this)); + return Mods[0].getModuleIdentifier(); } LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel, @@ -326,21 +394,17 @@ LTO::LTO(Config Conf, ThinBackend Backend, LTO::~LTO() = default; // Add the given symbol to the GlobalResolutions map, and resolve its partition. -void LTO::addSymbolToGlobalRes(SmallPtrSet<GlobalValue *, 8> &Used, - const InputFile::Symbol &Sym, +void LTO::addSymbolToGlobalRes(const InputFile::Symbol &Sym, SymbolResolution Res, unsigned Partition) { - GlobalValue *GV = Sym.isGV() ? Sym.getGV() : nullptr; - auto &GlobalRes = GlobalResolutions[Sym.getName()]; - if (GV) { - GlobalRes.UnnamedAddr &= GV->hasGlobalUnnamedAddr(); - if (Res.Prevailing) - GlobalRes.IRName = GV->getName(); - } + GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr(); + if (Res.Prevailing) + GlobalRes.IRName = Sym.getIRName(); + // Set the partition to external if we know it is used elsewhere, e.g. // it is visible to a regular object, is referenced from llvm.compiler_used, // or was already recorded as being referenced from a different partition. - if (Res.VisibleToRegularObj || (GV && Used.count(GV)) || + if (Res.VisibleToRegularObj || Sym.isUsed() || (GlobalRes.Partition != GlobalResolution::Unknown && GlobalRes.Partition != Partition)) { GlobalRes.Partition = GlobalResolution::External; @@ -372,6 +436,7 @@ static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, OS << 'x'; OS << '\n'; } + OS.flush(); assert(ResI == Res.end()); } @@ -383,41 +448,32 @@ Error LTO::add(std::unique_ptr<InputFile> Input, writeToResolutionFile(*Conf.ResolutionFile, Input.get(), Res); const SymbolResolution *ResI = Res.begin(); - for (InputFile::InputModule &IM : Input->Mods) - if (Error Err = addModule(*Input, IM, ResI, Res.end())) + for (unsigned I = 0; I != Input->Mods.size(); ++I) + if (Error Err = addModule(*Input, I, ResI, Res.end())) return Err; assert(ResI == Res.end()); return Error::success(); } -Error LTO::addModule(InputFile &Input, InputFile::InputModule &IM, +Error LTO::addModule(InputFile &Input, unsigned ModI, const SymbolResolution *&ResI, const SymbolResolution *ResE) { - // FIXME: move to backend - Module &M = *IM.Mod; - - if (M.getDataLayoutStr().empty()) - return make_error<StringError>("input module has no datalayout", - inconvertibleErrorCode()); - - if (!Conf.OverrideTriple.empty()) - M.setTargetTriple(Conf.OverrideTriple); - else if (M.getTargetTriple().empty()) - M.setTargetTriple(Conf.DefaultTriple); - - Expected<bool> HasThinLTOSummary = IM.BM.hasSummary(); + Expected<bool> HasThinLTOSummary = Input.Mods[ModI].hasSummary(); if (!HasThinLTOSummary) return HasThinLTOSummary.takeError(); + auto ModSyms = Input.module_symbols(ModI); if (*HasThinLTOSummary) - return addThinLTO(IM.BM, M, Input.module_symbols(IM), ResI, ResE); + return addThinLTO(Input.Mods[ModI], ModSyms, ResI, ResE); else - return addRegularLTO(IM.BM, ResI, ResE); + return addRegularLTO(Input.Mods[ModI], ModSyms, ResI, ResE); } // Add a regular LTO object to the link. -Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI, +Error LTO::addRegularLTO(BitcodeModule BM, + ArrayRef<InputFile::Symbol> Syms, + const SymbolResolution *&ResI, const SymbolResolution *ResE) { if (!RegularLTO.CombinedModule) { RegularLTO.CombinedModule = @@ -438,47 +494,84 @@ Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI, ModuleSymbolTable SymTab; SymTab.addModule(&M); - SmallPtrSet<GlobalValue *, 8> Used; - collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); - std::vector<GlobalValue *> Keep; for (GlobalVariable &GV : M.globals()) if (GV.hasAppendingLinkage()) Keep.push_back(&GV); - for (const InputFile::Symbol &Sym : - make_range(InputFile::symbol_iterator(SymTab.symbols().begin(), SymTab, - nullptr), - InputFile::symbol_iterator(SymTab.symbols().end(), SymTab, - nullptr))) { + DenseSet<GlobalObject *> AliasedGlobals; + for (auto &GA : M.aliases()) + if (GlobalObject *GO = GA.getBaseObject()) + AliasedGlobals.insert(GO); + + // In this function we need IR GlobalValues matching the symbols in Syms + // (which is not backed by a module), so we need to enumerate them in the same + // order. The symbol enumeration order of a ModuleSymbolTable intentionally + // matches the order of an irsymtab, but when we read the irsymtab in + // InputFile::create we omit some symbols that are irrelevant to LTO. The + // Skip() function skips the same symbols from the module as InputFile does + // from the symbol table. + auto MsymI = SymTab.symbols().begin(), MsymE = SymTab.symbols().end(); + auto Skip = [&]() { + while (MsymI != MsymE) { + auto Flags = SymTab.getSymbolFlags(*MsymI); + if ((Flags & object::BasicSymbolRef::SF_Global) && + !(Flags & object::BasicSymbolRef::SF_FormatSpecific)) + return; + ++MsymI; + } + }; + Skip(); + + for (const InputFile::Symbol &Sym : Syms) { assert(ResI != ResE); SymbolResolution Res = *ResI++; - addSymbolToGlobalRes(Used, Sym, Res, 0); - - if (Sym.getFlags() & object::BasicSymbolRef::SF_Undefined) - continue; - if (Res.Prevailing && Sym.isGV()) { - GlobalValue *GV = Sym.getGV(); - Keep.push_back(GV); - switch (GV->getLinkage()) { - default: - break; - case GlobalValue::LinkOnceAnyLinkage: - GV->setLinkage(GlobalValue::WeakAnyLinkage); - break; - case GlobalValue::LinkOnceODRLinkage: - GV->setLinkage(GlobalValue::WeakODRLinkage); - break; + addSymbolToGlobalRes(Sym, Res, 0); + + assert(MsymI != MsymE); + ModuleSymbolTable::Symbol Msym = *MsymI++; + Skip(); + + if (GlobalValue *GV = Msym.dyn_cast<GlobalValue *>()) { + if (Res.Prevailing) { + if (Sym.isUndefined()) + continue; + Keep.push_back(GV); + switch (GV->getLinkage()) { + default: + break; + case GlobalValue::LinkOnceAnyLinkage: + GV->setLinkage(GlobalValue::WeakAnyLinkage); + break; + case GlobalValue::LinkOnceODRLinkage: + GV->setLinkage(GlobalValue::WeakODRLinkage); + break; + } + } else if (isa<GlobalObject>(GV) && + (GV->hasLinkOnceODRLinkage() || GV->hasWeakODRLinkage() || + GV->hasAvailableExternallyLinkage()) && + !AliasedGlobals.count(cast<GlobalObject>(GV))) { + // Either of the above three types of linkage indicates that the + // chosen prevailing symbol will have the same semantics as this copy of + // the symbol, so we can link it with available_externally linkage. We + // only need to do this if the symbol is undefined. + GlobalValue *CombinedGV = + RegularLTO.CombinedModule->getNamedValue(GV->getName()); + if (!CombinedGV || CombinedGV->isDeclaration()) { + Keep.push_back(GV); + GV->setLinkage(GlobalValue::AvailableExternallyLinkage); + cast<GlobalObject>(GV)->setComdat(nullptr); + } } } // Common resolution: collect the maximum size/alignment over all commons. // We also record if we see an instance of a common as prevailing, so that // if none is prevailing we can ignore it later. - if (Sym.getFlags() & object::BasicSymbolRef::SF_Common) { + if (Sym.isCommon()) { // FIXME: We should figure out what to do about commons defined by asm. // For now they aren't reported correctly by ModuleSymbolTable. - auto &CommonRes = RegularLTO.Commons[Sym.getGV()->getName()]; + auto &CommonRes = RegularLTO.Commons[Sym.getIRName()]; CommonRes.Size = std::max(CommonRes.Size, Sym.getCommonSize()); CommonRes.Align = std::max(CommonRes.Align, Sym.getCommonAlignment()); CommonRes.Prevailing |= Res.Prevailing; @@ -486,23 +579,18 @@ Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI, // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit. } + assert(MsymI == MsymE); return RegularLTO.Mover->move(std::move(*MOrErr), Keep, [](GlobalValue &, IRMover::ValueAdder) {}, - /* LinkModuleInlineAsm */ true, /* IsPerformingImport */ false); } // Add a ThinLTO object to the link. -// FIXME: This function should not need to take as many parameters once we have -// a bitcode symbol table. -Error LTO::addThinLTO(BitcodeModule BM, Module &M, - iterator_range<InputFile::symbol_iterator> Syms, +Error LTO::addThinLTO(BitcodeModule BM, + ArrayRef<InputFile::Symbol> Syms, const SymbolResolution *&ResI, const SymbolResolution *ResE) { - SmallPtrSet<GlobalValue *, 8> Used; - collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); - Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr = BM.getSummary(); if (!SummaryOrErr) return SummaryOrErr.takeError(); @@ -512,11 +600,15 @@ Error LTO::addThinLTO(BitcodeModule BM, Module &M, for (const InputFile::Symbol &Sym : Syms) { assert(ResI != ResE); SymbolResolution Res = *ResI++; - addSymbolToGlobalRes(Used, Sym, Res, ThinLTO.ModuleMap.size() + 1); + addSymbolToGlobalRes(Sym, Res, ThinLTO.ModuleMap.size() + 1); - if (Res.Prevailing && Sym.isGV()) - ThinLTO.PrevailingModuleForGUID[Sym.getGV()->getGUID()] = - BM.getModuleIdentifier(); + if (Res.Prevailing) { + if (!Sym.getIRName().empty()) { + auto GUID = GlobalValue::getGUID(GlobalValue::getGlobalIdentifier( + Sym.getIRName(), GlobalValue::ExternalLinkage, "")); + ThinLTO.PrevailingModuleForGUID[GUID] = BM.getModuleIdentifier(); + } + } } if (!ThinLTO.ModuleMap.insert({BM.getModuleIdentifier(), BM}).second) @@ -602,7 +694,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { return Error::success(); } return backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel, - std::move(RegularLTO.CombinedModule)); + std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex); } /// This class defines the interface to the ThinLTO backend. @@ -633,6 +725,7 @@ class InProcessThinBackend : public ThinBackendProc { ThreadPool BackendThreadPool; AddStreamFn AddStream; NativeObjectCache Cache; + TypeIdSummariesByGuidTy TypeIdSummariesByGuid; Optional<Error> Err; std::mutex ErrMu; @@ -645,7 +738,14 @@ public: AddStreamFn AddStream, NativeObjectCache Cache) : ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries), BackendThreadPool(ThinLTOParallelismLevel), - AddStream(std::move(AddStream)), Cache(std::move(Cache)) {} + AddStream(std::move(AddStream)), Cache(std::move(Cache)) { + // Create a mapping from type identifier GUIDs to type identifier summaries. + // This allows backends to use the type identifier GUIDs stored in the + // function summaries to determine which type identifier summaries affect + // each function without needing to compute GUIDs in each backend. + for (auto &TId : CombinedIndex.typeIds()) + TypeIdSummariesByGuid[GlobalValue::getGUID(TId.first)].push_back(&TId); + } Error runThinLTOBackendThread( AddStreamFn AddStream, NativeObjectCache Cache, unsigned Task, @@ -654,7 +754,8 @@ public: const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector<StringRef, BitcodeModule> &ModuleMap) { + MapVector<StringRef, BitcodeModule> &ModuleMap, + const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) { auto RunThinBackend = [&](AddStreamFn AddStream) { LTOLLVMContext BackendContext(Conf); Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext); @@ -677,7 +778,7 @@ public: SmallString<40> Key; // The module may be cached, this helps handling it. computeCacheKey(Key, Conf, CombinedIndex, ModuleID, ImportList, ExportList, - ResolvedODR, DefinedGlobals); + ResolvedODR, DefinedGlobals, TypeIdSummariesByGuid); if (AddStreamFn CacheAddStream = Cache(Task, Key)) return RunThinBackend(CacheAddStream); @@ -701,10 +802,11 @@ public: const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector<StringRef, BitcodeModule> &ModuleMap) { + MapVector<StringRef, BitcodeModule> &ModuleMap, + const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) { Error E = runThinLTOBackendThread( - AddStream, Cache, Task, BM, CombinedIndex, ImportList, - ExportList, ResolvedODR, DefinedGlobals, ModuleMap); + AddStream, Cache, Task, BM, CombinedIndex, ImportList, ExportList, + ResolvedODR, DefinedGlobals, ModuleMap, TypeIdSummariesByGuid); if (E) { std::unique_lock<std::mutex> L(ErrMu); if (Err) @@ -713,9 +815,9 @@ public: Err = std::move(E); } }, - BM, std::ref(CombinedIndex), std::ref(ImportList), - std::ref(ExportList), std::ref(ResolvedODR), std::ref(DefinedGlobals), - std::ref(ModuleMap)); + BM, std::ref(CombinedIndex), std::ref(ImportList), std::ref(ExportList), + std::ref(ResolvedODR), std::ref(DefinedGlobals), std::ref(ModuleMap), + std::ref(TypeIdSummariesByGuid)); return Error::success(); } @@ -857,19 +959,6 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, if (!ModuleToDefinedGVSummaries.count(Mod.first)) ModuleToDefinedGVSummaries.try_emplace(Mod.first); - // Compute "dead" symbols, we don't want to import/export these! - DenseSet<GlobalValue::GUID> GUIDPreservedSymbols; - for (auto &Res : GlobalResolutions) { - if (Res.second.VisibleOutsideThinLTO && - // IRName will be defined if we have seen the prevailing copy of - // this value. If not, no need to preserve any ThinLTO copies. - !Res.second.IRName.empty()) - GUIDPreservedSymbols.insert(GlobalValue::getGUID(Res.second.IRName)); - } - - auto DeadSymbols = - computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols); - StringMap<FunctionImporter::ImportMapTy> ImportLists( ThinLTO.ModuleMap.size()); StringMap<FunctionImporter::ExportSetTy> ExportLists( @@ -877,6 +966,20 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; if (Conf.OptLevel > 0) { + // Compute "dead" symbols, we don't want to import/export these! + DenseSet<GlobalValue::GUID> GUIDPreservedSymbols; + for (auto &Res : GlobalResolutions) { + if (Res.second.VisibleOutsideThinLTO && + // IRName will be defined if we have seen the prevailing copy of + // this value. If not, no need to preserve any ThinLTO copies. + !Res.second.IRName.empty()) + GUIDPreservedSymbols.insert(GlobalValue::getGUID( + GlobalValue::getRealLinkageName(Res.second.IRName))); + } + + auto DeadSymbols = + computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols); + ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, ImportLists, ExportLists, &DeadSymbols); @@ -890,10 +993,11 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, // partition (and we can't get the GUID). if (Res.second.IRName.empty()) continue; - auto GUID = GlobalValue::getGUID(Res.second.IRName); + auto GUID = GlobalValue::getGUID( + GlobalValue::getRealLinkageName(Res.second.IRName)); // Mark exported unless index-based analysis determined it to be dead. if (!DeadSymbols.count(GUID)) - ExportedGUIDs.insert(GlobalValue::getGUID(Res.second.IRName)); + ExportedGUIDs.insert(GUID); } auto isPrevailing = [&](GlobalValue::GUID GUID, @@ -937,3 +1041,27 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, return BackendProc->wait(); } + +Expected<std::unique_ptr<tool_output_file>> +lto::setupOptimizationRemarks(LLVMContext &Context, + StringRef LTORemarksFilename, + bool LTOPassRemarksWithHotness, int Count) { + if (LTORemarksFilename.empty()) + return nullptr; + + std::string Filename = LTORemarksFilename; + if (Count != -1) + Filename += ".thin." + llvm::utostr(Count) + ".yaml"; + + std::error_code EC; + auto DiagnosticFile = + llvm::make_unique<tool_output_file>(Filename, EC, sys::fs::F_None); + if (EC) + return errorCodeToError(EC); + Context.setDiagnosticsOutputFile( + llvm::make_unique<yaml::Output>(DiagnosticFile->os())); + if (LTOPassRemarksWithHotness) + Context.setDiagnosticHotnessRequested(true); + DiagnosticFile->keep(); + return std::move(DiagnosticFile); +} diff --git a/lib/LTO/LTOBackend.cpp b/lib/LTO/LTOBackend.cpp index 809db80bc9163..4bd251f727a43 100644 --- a/lib/LTO/LTOBackend.cpp +++ b/lib/LTO/LTOBackend.cpp @@ -27,6 +27,7 @@ #include "llvm/LTO/LTO.h" #include "llvm/LTO/legacy/UpdateCompilerUsed.h" #include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/ModuleSymbolTable.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -42,6 +43,11 @@ using namespace llvm; using namespace lto; +static cl::opt<bool> + LTOUseNewPM("lto-use-new-pm", + cl::desc("Run LTO passes using the new pass manager"), + cl::init(false), cl::Hidden); + LLVM_ATTRIBUTE_NORETURN static void reportOpenError(StringRef Path, Twine Msg) { errs() << "failed to open " << Path << ": " << Msg << '\n'; errs().flush(); @@ -124,6 +130,56 @@ createTargetMachine(Config &Conf, StringRef TheTriple, Conf.CodeModel, Conf.CGOptLevel)); } +static void runNewPMPasses(Module &Mod, TargetMachine *TM, unsigned OptLevel) { + PassBuilder PB(TM); + AAManager AA; + + // Parse a custom AA pipeline if asked to. + assert(PB.parseAAPipeline(AA, "default")); + + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + + // Register the AA manager first so that our version is the one used. + FAM.registerPass([&] { return std::move(AA); }); + + // Register all the basic analyses with the managers. + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM; + // FIXME (davide): verify the input. + + PassBuilder::OptimizationLevel OL; + + switch (OptLevel) { + default: + llvm_unreachable("Invalid optimization level"); + case 0: + OL = PassBuilder::O0; + break; + case 1: + OL = PassBuilder::O1; + break; + case 2: + OL = PassBuilder::O2; + break; + case 3: + OL = PassBuilder::O3; + break; + } + + MPM = PB.buildLTODefaultPipeline(OL, false /* DebugLogging */); + MPM.run(Mod, MAM); + + // FIXME (davide): verify the output. +} + static void runNewPMCustomPasses(Module &Mod, TargetMachine *TM, std::string PipelineDesc, std::string AAPipelineDesc, @@ -168,13 +224,16 @@ static void runNewPMCustomPasses(Module &Mod, TargetMachine *TM, } static void runOldPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, - bool IsThinLTO) { + bool IsThinLTO, ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) { legacy::PassManager passes; passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); PassManagerBuilder PMB; PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple())); PMB.Inliner = createFunctionInliningPass(); + PMB.ExportSummary = ExportSummary; + PMB.ImportSummary = ImportSummary; // Unconditionally verify input since it is not verified before this // point and has unknown origin. PMB.VerifyInput = true; @@ -191,12 +250,21 @@ static void runOldPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, } bool opt(Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, - bool IsThinLTO) { - if (Conf.OptPipeline.empty()) - runOldPMPasses(Conf, Mod, TM, IsThinLTO); - else + bool IsThinLTO, ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) { + // There's still no ThinLTO pipeline hooked up in the new pass manager, + // once there is one, we can just remove this. + if (LTOUseNewPM && IsThinLTO) + report_fatal_error("ThinLTO not supported with the new PM yet!"); + + // FIXME: Plumb the combined index into the new pass manager. + if (!Conf.OptPipeline.empty()) runNewPMCustomPasses(Mod, TM, Conf.OptPipeline, Conf.AAPipeline, Conf.DisableVerify); + else if (LTOUseNewPM) + runNewPMPasses(Mod, TM, Conf.OptLevel); + else + runOldPMPasses(Conf, Mod, TM, IsThinLTO, ExportSummary, ImportSummary); return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } @@ -207,8 +275,7 @@ void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, auto Stream = AddStream(Task); legacy::PassManager CodeGenPasses; - if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, - TargetMachine::CGFT_ObjectFile)) + if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, Conf.CGFileType)) report_fatal_error("Failed to setup codegen"); CodeGenPasses.run(Mod); } @@ -276,12 +343,22 @@ Expected<const Target *> initAndLookupTarget(Config &C, Module &Mod) { } +static void +finalizeOptimizationRemarks(std::unique_ptr<tool_output_file> DiagOutputFile) { + // Make sure we flush the diagnostic remarks file in case the linker doesn't + // call the global destructors before exiting. + if (!DiagOutputFile) + return; + DiagOutputFile->keep(); + DiagOutputFile->os().flush(); +} + static void handleAsmUndefinedRefs(Module &Mod, TargetMachine &TM) { // Collect the list of undefined symbols used in asm and update // llvm.compiler.used to prevent optimization to drop these from the output. StringSet<> AsmUndefinedRefs; ModuleSymbolTable::CollectAsmSymbols( - Triple(Mod.getTargetTriple()), Mod.getModuleInlineAsm(), + Mod, [&AsmUndefinedRefs](StringRef Name, object::BasicSymbolRef::Flags Flags) { if (Flags & object::BasicSymbolRef::SF_Undefined) AsmUndefinedRefs.insert(Name); @@ -291,7 +368,8 @@ static void handleAsmUndefinedRefs(Module &Mod, TargetMachine &TM) { Error lto::backend(Config &C, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, - std::unique_ptr<Module> Mod) { + std::unique_ptr<Module> Mod, + ModuleSummaryIndex &CombinedIndex) { Expected<const Target *> TOrErr = initAndLookupTarget(C, *Mod); if (!TOrErr) return TOrErr.takeError(); @@ -301,9 +379,20 @@ Error lto::backend(Config &C, AddStreamFn AddStream, handleAsmUndefinedRefs(*Mod, *TM); - if (!C.CodeGenOnly) - if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false)) + // Setup optimization remarks. + auto DiagFileOrErr = lto::setupOptimizationRemarks( + Mod->getContext(), C.RemarksFilename, 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)) { + finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); return Error::success(); + } + } if (ParallelCodeGenParallelismLevel == 1) { codegen(C, TM.get(), AddStream, 0, *Mod); @@ -311,11 +400,12 @@ Error lto::backend(Config &C, AddStreamFn AddStream, splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel, std::move(Mod)); } + finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); return Error::success(); } Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, - Module &Mod, ModuleSummaryIndex &CombinedIndex, + Module &Mod, const ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector<StringRef, BitcodeModule> &ModuleMap) { @@ -367,7 +457,8 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, if (Conf.PostImportModuleHook && !Conf.PostImportModuleHook(Task, Mod)) return Error::success(); - if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLTO=*/true)) + if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLTO=*/true, + /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex)) return Error::success(); codegen(Conf, TM.get(), AddStream, Task, Mod); diff --git a/lib/LTO/LTOCodeGenerator.cpp b/lib/LTO/LTOCodeGenerator.cpp index 6af31e61f9463..86fba843e980b 100644 --- a/lib/LTO/LTOCodeGenerator.cpp +++ b/lib/LTO/LTOCodeGenerator.cpp @@ -35,6 +35,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/InitializePasses.h" +#include "llvm/LTO/LTO.h" #include "llvm/LTO/legacy/LTOModule.h" #include "llvm/LTO/legacy/UpdateCompilerUsed.h" #include "llvm/Linker/Linker.h" @@ -140,6 +141,7 @@ void LTOCodeGenerator::initializeLTOPasses() { initializeMemCpyOptLegacyPassPass(R); initializeDCELegacyPassPass(R); initializeCFGSimplifyPassPass(R); + initializeLateCFGSimplifyPassPass(R); } void LTOCodeGenerator::setAsmUndefinedRefs(LTOModule *Mod) { @@ -506,25 +508,6 @@ void LTOCodeGenerator::verifyMergedModuleOnce() { report_fatal_error("Broken module found, compilation aborted!"); } -bool LTOCodeGenerator::setupOptimizationRemarks() { - if (LTORemarksFilename != "") { - std::error_code EC; - DiagnosticOutputFile = llvm::make_unique<tool_output_file>( - LTORemarksFilename, EC, sys::fs::F_None); - if (EC) { - emitError(EC.message()); - return false; - } - Context.setDiagnosticsOutputFile( - llvm::make_unique<yaml::Output>(DiagnosticOutputFile->os())); - } - - if (LTOPassRemarksWithHotness) - Context.setDiagnosticHotnessRequested(true); - - return true; -} - void LTOCodeGenerator::finishOptimizationRemarks() { if (DiagnosticOutputFile) { DiagnosticOutputFile->keep(); @@ -540,8 +523,13 @@ bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline, if (!this->determineTarget()) return false; - if (!setupOptimizationRemarks()) - return false; + auto DiagFileOrErr = lto::setupOptimizationRemarks( + Context, LTORemarksFilename, LTOPassRemarksWithHotness); + if (!DiagFileOrErr) { + errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; + report_fatal_error("Can't get an output file for the remarks"); + } + DiagnosticOutputFile = std::move(*DiagFileOrErr); // We always run the verifier once on the merged module, the `DisableVerify` // parameter only applies to subsequent verify. @@ -567,6 +555,8 @@ bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline, if (!DisableInline) PMB.Inliner = createFunctionInliningPass(); PMB.LibraryInfo = new TargetLibraryInfoImpl(TargetTriple); + if (Freestanding) + PMB.LibraryInfo->disableAllFunctions(); PMB.OptLevel = OptLevel; PMB.VerifyInput = !DisableVerify; PMB.VerifyOutput = !DisableVerify; diff --git a/lib/LTO/LTOModule.cpp b/lib/LTO/LTOModule.cpp index 89aeb80000388..11f0982c6a602 100644 --- a/lib/LTO/LTOModule.cpp +++ b/lib/LTO/LTOModule.cpp @@ -14,11 +14,12 @@ #include "llvm/LTO/legacy/LTOModule.h" #include "llvm/ADT/Triple.h" +#include "llvm/Analysis/ObjectUtils.h" #include "llvm/Bitcode/BitcodeReader.h" -#include "llvm/CodeGen/Analysis.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Mangler.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCExpr.h" @@ -647,11 +648,15 @@ void LTOModule::parseMetadata() { } } - // Globals + // Globals - we only need to do this for COFF. + const Triple TT(_target->getTargetTriple()); + if (!TT.isOSBinFormatCOFF()) + return; + Mangler M; for (const NameAndAttributes &Sym : _symbols) { if (!Sym.symbol) continue; - _target->getObjFileLowering()->emitLinkerFlagsForGlobal(OS, Sym.symbol); + emitLinkerFlagsForGlobalCOFF(OS, Sym.symbol, TT, M); } // Add other interesting metadata here. diff --git a/lib/LTO/ThinLTOCodeGenerator.cpp b/lib/LTO/ThinLTOCodeGenerator.cpp index 40537e4fa784a..0d845a26d0c2e 100644 --- a/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/lib/LTO/ThinLTOCodeGenerator.cpp @@ -14,10 +14,6 @@ #include "llvm/LTO/legacy/ThinLTOCodeGenerator.h" -#ifdef HAVE_LLVM_REVISION -#include "LLVMLTORevision.h" -#endif - #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/ModuleSummaryAnalysis.h" @@ -47,6 +43,7 @@ #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VCSRevision.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/FunctionImport.h" @@ -73,27 +70,6 @@ namespace { static cl::opt<int> ThreadCount("threads", cl::init(llvm::heavyweight_hardware_concurrency())); -Expected<std::unique_ptr<tool_output_file>> -setupOptimizationRemarks(LLVMContext &Ctx, int Count) { - if (LTOPassRemarksWithHotness) - Ctx.setDiagnosticHotnessRequested(true); - - if (LTORemarksFilename.empty()) - return nullptr; - - std::string FileName = - LTORemarksFilename + ".thin." + llvm::utostr(Count) + ".yaml"; - std::error_code EC; - auto DiagnosticOutputFile = - llvm::make_unique<tool_output_file>(FileName, EC, sys::fs::F_None); - if (EC) - return errorCodeToError(EC); - Ctx.setDiagnosticsOutputFile( - llvm::make_unique<yaml::Output>(DiagnosticOutputFile->os())); - DiagnosticOutputFile->keep(); - return std::move(DiagnosticOutputFile); -} - // Simple helper to save temporary files for debug. static void saveTempBitcode(const Module &TheModule, StringRef TempDir, unsigned count, StringRef Suffix) { @@ -208,10 +184,12 @@ crossImportIntoModule(Module &TheModule, const ModuleSummaryIndex &Index, } static void optimizeModule(Module &TheModule, TargetMachine &TM, - unsigned OptLevel) { + unsigned OptLevel, bool Freestanding) { // Populate the PassManager PassManagerBuilder PMB; PMB.LibraryInfo = new TargetLibraryInfoImpl(TM.getTargetTriple()); + if (Freestanding) + PMB.LibraryInfo->disableAllFunctions(); PMB.Inliner = createFunctionInliningPass(); // FIXME: should get it from the bitcode? PMB.OptLevel = OptLevel; @@ -285,7 +263,7 @@ public: const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedFunctions, const DenseSet<GlobalValue::GUID> &PreservedSymbols, unsigned OptLevel, - const TargetMachineBuilder &TMBuilder) { + bool Freestanding, const TargetMachineBuilder &TMBuilder) { if (CachePath.empty()) return; @@ -323,7 +301,7 @@ public: // Start with the compiler revision Hasher.update(LLVM_VERSION_STRING); -#ifdef HAVE_LLVM_REVISION +#ifdef LLVM_REVISION Hasher.update(LLVM_REVISION); #endif @@ -342,6 +320,7 @@ public: AddUnsigned(*TMBuilder.RelocModel); AddUnsigned(TMBuilder.CGOptLevel); AddUnsigned(OptLevel); + AddUnsigned(Freestanding); Hasher.update(ArrayRef<uint8_t>((uint8_t *)&ModHash[0], sizeof(ModHash))); for (auto F : ExportList) @@ -369,7 +348,10 @@ public: ArrayRef<uint8_t>((const uint8_t *)&Entry, sizeof(GlobalValue::GUID))); } - sys::path::append(EntryPath, CachePath, toHex(Hasher.result())); + // This choice of file name allows the cache to be pruned (see pruneCache() + // in include/llvm/Support/CachePruning.h). + sys::path::append(EntryPath, CachePath, + "llvmcache-" + toHex(Hasher.result())); } // Access the path to this entry in the cache. @@ -422,7 +404,7 @@ ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index, const GVSummaryMapTy &DefinedGlobals, const ThinLTOCodeGenerator::CachingOptions &CacheOptions, bool DisableCodeGen, StringRef SaveTempsDir, - unsigned OptLevel, unsigned count) { + bool Freestanding, unsigned OptLevel, unsigned count) { // "Benchmark"-like optimization: single-source case bool SingleModule = (ModuleMap.size() == 1); @@ -454,7 +436,7 @@ ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index, saveTempBitcode(TheModule, SaveTempsDir, count, ".3.imported.bc"); } - optimizeModule(TheModule, TM, OptLevel); + optimizeModule(TheModule, TM, OptLevel, Freestanding); saveTempBitcode(TheModule, SaveTempsDir, count, ".4.opt.bc"); @@ -780,7 +762,7 @@ void ThinLTOCodeGenerator::optimize(Module &TheModule) { initTMBuilder(TMBuilder, Triple(TheModule.getTargetTriple())); // Optimize now - optimizeModule(TheModule, *TMBuilder.create(), OptLevel); + optimizeModule(TheModule, *TMBuilder.create(), OptLevel, Freestanding); } /** @@ -966,7 +948,7 @@ void ThinLTOCodeGenerator::run() { ImportLists[ModuleIdentifier], ExportList, ResolvedODR[ModuleIdentifier], DefinedFunctions, GUIDPreservedSymbols, - OptLevel, TMBuilder); + OptLevel, Freestanding, TMBuilder); auto CacheEntryPath = CacheEntry.getEntryPath(); { @@ -990,7 +972,8 @@ void ThinLTOCodeGenerator::run() { LLVMContext Context; Context.setDiscardValueNames(LTODiscardValueNames); Context.enableDebugTypeODRUniquing(); - auto DiagFileOrErr = setupOptimizationRemarks(Context, count); + auto DiagFileOrErr = lto::setupOptimizationRemarks( + Context, LTORemarksFilename, LTOPassRemarksWithHotness, count); if (!DiagFileOrErr) { errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; report_fatal_error("ThinLTO: Can't get an output file for the " @@ -1011,7 +994,7 @@ void ThinLTOCodeGenerator::run() { *TheModule, *Index, ModuleMap, *TMBuilder.create(), ImportList, ExportList, GUIDPreservedSymbols, ModuleToDefinedGVSummaries[ModuleIdentifier], CacheOptions, - DisableCodeGen, SaveTempsDir, OptLevel, count); + DisableCodeGen, SaveTempsDir, Freestanding, OptLevel, count); // Commit to the cache (if enabled) CacheEntry.write(*OutputBuffer); @@ -1043,11 +1026,7 @@ void ThinLTOCodeGenerator::run() { } } - CachePruning(CacheOptions.Path) - .setPruningInterval(std::chrono::seconds(CacheOptions.PruningInterval)) - .setEntryExpiration(std::chrono::seconds(CacheOptions.Expiration)) - .setMaxSize(CacheOptions.MaxPercentageOfAvailableSpace) - .prune(); + pruneCache(CacheOptions.Path, CacheOptions.Policy); // If statistics were requested, print them out now. if (llvm::AreStatisticsEnabled()) diff --git a/lib/LTO/UpdateCompilerUsed.cpp b/lib/LTO/UpdateCompilerUsed.cpp index b67d9ea5989d5..5165cc9650387 100644 --- a/lib/LTO/UpdateCompilerUsed.cpp +++ b/lib/LTO/UpdateCompilerUsed.cpp @@ -65,7 +65,7 @@ private: // target. for (unsigned I = 0, E = static_cast<unsigned>(LibFunc::NumLibFuncs); I != E; ++I) { - LibFunc::Func F = static_cast<LibFunc::Func>(I); + LibFunc F = static_cast<LibFunc>(I); if (TLI.has(F)) Libcalls.insert(TLI.getName(F)); } |