diff options
Diffstat (limited to 'contrib/llvm/lib/LTO')
-rw-r--r-- | contrib/llvm/lib/LTO/Caching.cpp | 82 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/LTO.cpp | 655 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/LTOBackend.cpp | 142 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/LTOCodeGenerator.cpp | 48 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/LTOModule.cpp | 23 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp | 176 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/UpdateCompilerUsed.cpp | 2 |
7 files changed, 696 insertions, 432 deletions
diff --git a/contrib/llvm/lib/LTO/Caching.cpp b/contrib/llvm/lib/LTO/Caching.cpp index fd5bdb0..e32e46c 100644 --- a/contrib/llvm/lib/LTO/Caching.cpp +++ b/contrib/llvm/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/contrib/llvm/lib/LTO/LTO.cpp b/contrib/llvm/lib/LTO/LTO.cpp index e3e2f9f..1997394 100644 --- a/contrib/llvm/lib/LTO/LTO.cpp +++ b/contrib/llvm/lib/LTO/LTO.cpp @@ -20,9 +20,12 @@ #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/ModuleSummaryIndexObjectFile.h" +#include "llvm/Object/IRObjectFile.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -31,6 +34,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 +50,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 +64,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 +74,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 +91,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 @@ -91,10 +114,15 @@ static void computeCacheKey( AddUnsigned((unsigned)Conf.Options.DebuggerTuning); for (auto &A : Conf.MAttrs) AddString(A); - AddUnsigned(Conf.RelocModel); + if (Conf.RelocModel) + AddUnsigned(*Conf.RelocModel); + else + AddUnsigned(-1); AddUnsigned(Conf.CodeModel); AddUnsigned(Conf.CGOptLevel); + AddUnsigned(Conf.CGFileType); AddUnsigned(Conf.OptLevel); + AddUnsigned(Conf.UseNewPM); AddString(Conf.OptPipeline); AddString(Conf.AAPipeline); AddString(Conf.OverrideTriple); @@ -107,10 +135,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 +155,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 +254,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()); @@ -190,13 +278,14 @@ void llvm::thinLTOResolveWeakForLinkerInIndex( // when needed. DenseSet<GlobalValueSummary *> GlobalInvolvedWithAlias; for (auto &I : Index) - for (auto &S : I.second) + for (auto &S : I.second.SummaryList) if (auto AS = dyn_cast<AliasSummary>(S.get())) GlobalInvolvedWithAlias.insert(&AS->getAliasee()); for (auto &I : Index) - thinLTOResolveWeakForLinkerGUID(I.second, I.first, GlobalInvolvedWithAlias, - isPrevailing, recordNewLinkage); + thinLTOResolveWeakForLinkerGUID(I.second.SummaryList, I.first, + GlobalInvolvedWithAlias, isPrevailing, + recordNewLinkage); } static void thinLTOInternalizeAndPromoteGUID( @@ -217,92 +306,42 @@ void llvm::thinLTOInternalizeAndPromoteInIndex( ModuleSummaryIndex &Index, function_ref<bool(StringRef, GlobalValue::GUID)> isExported) { for (auto &I : Index) - thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported); + thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, 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; Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) { std::unique_ptr<InputFile> File(new InputFile); - ErrorOr<MemoryBufferRef> BCOrErr = - IRObjectFile::findBitcodeInMemBuffer(Object); - if (!BCOrErr) - return errorCodeToError(BCOrErr.getError()); - - Expected<std::vector<BitcodeModule>> BMsOrErr = - getBitcodeModuleList(*BCOrErr); - if (!BMsOrErr) - return BMsOrErr.takeError(); - - if (BMsOrErr->empty()) - 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. - for (auto BM : *BMsOrErr) { - Expected<std::unique_ptr<Module>> MOrErr = - BM.getLazyModule(File->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(); - - 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()); - } - - File->Mods.push_back({BM, std::move(*MOrErr), SymBegin, SymEnd}); + Expected<IRSymtabFile> FOrErr = readIRSymtab(Object); + if (!FOrErr) + return FOrErr.takeError(); + + File->TargetTriple = FOrErr->TheReader.getTargetTriple(); + File->SourceFileName = FOrErr->TheReader.getSourceFileName(); + File->COFFLinkerOpts = FOrErr->TheReader.getCOFFLinkerOpts(); + File->ComdatTable = FOrErr->TheReader.getComdatTable(); + + for (unsigned I = 0; I != FOrErr->Mods.size(); ++I) { + size_t Begin = File->Symbols.size(); + for (const irsymtab::Reader::SymbolRef &Sym : + FOrErr->TheReader.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()}); } + File->Mods = FOrErr->Mods; + File->Strtab = std::move(FOrErr->Strtab); 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, @@ -325,33 +364,40 @@ LTO::LTO(Config Conf, ThinBackend Backend, // Requires a destructor for MapVector<BitcodeModule>. 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, - SymbolResolution Res, unsigned Partition) { - GlobalValue *GV = Sym.isGV() ? Sym.getGV() : nullptr; +// Add the symbols in the given module to the GlobalResolutions map, and resolve +// their partitions. +void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms, + ArrayRef<SymbolResolution> Res, + unsigned Partition, bool InSummary) { + auto *ResI = Res.begin(); + auto *ResE = Res.end(); + (void)ResE; + for (const InputFile::Symbol &Sym : Syms) { + assert(ResI != ResE); + SymbolResolution Res = *ResI++; - auto &GlobalRes = GlobalResolutions[Sym.getName()]; - if (GV) { - GlobalRes.UnnamedAddr &= GV->hasGlobalUnnamedAddr(); + auto &GlobalRes = GlobalResolutions[Sym.getName()]; + GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr(); if (Res.Prevailing) - GlobalRes.IRName = GV->getName(); + GlobalRes.IRName = Sym.getIRName(); + + // Set the partition to external if we know it is re-defined by the linker + // with -defsym or -wrap options, 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.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() || + (GlobalRes.Partition != GlobalResolution::Unknown && + GlobalRes.Partition != Partition)) { + GlobalRes.Partition = GlobalResolution::External; + } else + // First recorded reference, save the current partition. + GlobalRes.Partition = Partition; + + // Flag as visible outside of summary if visible from a regular object or + // from a module that does not have a summary. + GlobalRes.VisibleOutsideSummary |= + (Res.VisibleToRegularObj || Sym.isUsed() || !InSummary); } - // 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)) || - (GlobalRes.Partition != GlobalResolution::Unknown && - GlobalRes.Partition != Partition)) { - GlobalRes.Partition = GlobalResolution::External; - } else - // First recorded reference, save the current partition. - GlobalRes.Partition = Partition; - - // Flag as visible outside of ThinLTO if visible from a regular object or - // if this is a reference in the regular LTO partition. - GlobalRes.VisibleOutsideThinLTO |= - (Res.VisibleToRegularObj || (Partition == GlobalResolution::RegularLTO)); } static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, @@ -370,8 +416,11 @@ static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, OS << 'l'; if (Res.VisibleToRegularObj) OS << 'x'; + if (Res.LinkerRedefined) + OS << 'r'; OS << '\n'; } + OS.flush(); assert(ResI == Res.end()); } @@ -383,102 +432,174 @@ 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(); - if (!HasThinLTOSummary) - return HasThinLTOSummary.takeError(); + Expected<BitcodeLTOInfo> LTOInfo = Input.Mods[ModI].getLTOInfo(); + if (!LTOInfo) + return LTOInfo.takeError(); + + BitcodeModule BM = Input.Mods[ModI]; + auto ModSyms = Input.module_symbols(ModI); + addModuleToGlobalRes(ModSyms, {ResI, ResE}, + LTOInfo->IsThinLTO ? ThinLTO.ModuleMap.size() + 1 : 0, + LTOInfo->HasSummary); + + if (LTOInfo->IsThinLTO) + return addThinLTO(BM, ModSyms, ResI, ResE); + + Expected<RegularLTOState::AddedModule> ModOrErr = + addRegularLTO(BM, ModSyms, ResI, ResE); + if (!ModOrErr) + return ModOrErr.takeError(); + + if (!LTOInfo->HasSummary) + return linkRegularLTO(std::move(*ModOrErr), /*LivenessFromIndex=*/false); + + // Regular LTO module summaries are added to a dummy module that represents + // the combined regular LTO module. + if (Error Err = BM.readSummary(ThinLTO.CombinedIndex, "", -1ull)) + return Err; + RegularLTO.ModsWithSummaries.push_back(std::move(*ModOrErr)); + return Error::success(); +} - if (*HasThinLTOSummary) - return addThinLTO(IM.BM, M, Input.module_symbols(IM), ResI, ResE); - else - return addRegularLTO(IM.BM, ResI, ResE); +// Checks whether the given global value is in a non-prevailing comdat +// (comdat containing values the linker indicated were not prevailing, +// which we then dropped to available_externally), and if so, removes +// it from the comdat. This is called for all global values to ensure the +// comdat is empty rather than leaving an incomplete comdat. It is needed for +// regular LTO modules, in case we are in a mixed-LTO mode (both regular +// and thin LTO modules) compilation. Since the regular LTO module will be +// linked first in the final native link, we want to make sure the linker +// doesn't select any of these incomplete comdats that would be left +// in the regular LTO module without this cleanup. +static void +handleNonPrevailingComdat(GlobalValue &GV, + std::set<const Comdat *> &NonPrevailingComdats) { + Comdat *C = GV.getComdat(); + if (!C) + return; + + if (!NonPrevailingComdats.count(C)) + return; + + // Additionally need to drop externally visible global values from the comdat + // to available_externally, so that there aren't multiply defined linker + // errors. + if (!GV.hasLocalLinkage()) + GV.setLinkage(GlobalValue::AvailableExternallyLinkage); + + if (auto GO = dyn_cast<GlobalObject>(&GV)) + GO->setComdat(nullptr); } // Add a regular LTO object to the link. -Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI, - const SymbolResolution *ResE) { - if (!RegularLTO.CombinedModule) { - RegularLTO.CombinedModule = - llvm::make_unique<Module>("ld-temp.o", RegularLTO.Ctx); - RegularLTO.Mover = llvm::make_unique<IRMover>(*RegularLTO.CombinedModule); - } +// The resulting module needs to be linked into the combined LTO module with +// linkRegularLTO. +Expected<LTO::RegularLTOState::AddedModule> +LTO::addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms, + const SymbolResolution *&ResI, + const SymbolResolution *ResE) { + RegularLTOState::AddedModule Mod; Expected<std::unique_ptr<Module>> MOrErr = BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true, /*IsImporting*/ false); if (!MOrErr) return MOrErr.takeError(); - Module &M = **MOrErr; + Mod.M = std::move(*MOrErr); + if (Error Err = M.materializeMetadata()) - return Err; + return std::move(Err); UpgradeDebugInfo(M); 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); + Mod.Keep.push_back(&GV); + + 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 : - make_range(InputFile::symbol_iterator(SymTab.symbols().begin(), SymTab, - nullptr), - InputFile::symbol_iterator(SymTab.symbols().end(), SymTab, - nullptr))) { + std::set<const Comdat *> NonPrevailingComdats; + 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; + assert(MsymI != MsymE); + ModuleSymbolTable::Symbol Msym = *MsymI++; + Skip(); + + if (GlobalValue *GV = Msym.dyn_cast<GlobalValue *>()) { + if (Res.Prevailing) { + if (Sym.isUndefined()) + continue; + Mod.Keep.push_back(GV); + // For symbols re-defined with linker -wrap and -defsym options, + // set the linkage to weak to inhibit IPO. The linkage will be + // restored by the linker. + if (Res.LinkerRedefined) + GV->setLinkage(GlobalValue::WeakAnyLinkage); + + GlobalValue::LinkageTypes OriginalLinkage = GV->getLinkage(); + if (GlobalValue::isLinkOnceLinkage(OriginalLinkage)) + GV->setLinkage(GlobalValue::getWeakLinkage( + GlobalValue::isLinkOnceODRLinkage(OriginalLinkage))); + } else if (isa<GlobalObject>(GV) && + (GV->hasLinkOnceODRLinkage() || GV->hasWeakODRLinkage() || + GV->hasAvailableExternallyLinkage()) && + !AliasedGlobals.count(cast<GlobalObject>(GV))) { + // Any 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 may be able to link it with available_externally + // linkage. We will decide later whether to do that when we link this + // module (in linkRegularLTO), based on whether it is undefined. + Mod.Keep.push_back(GV); + GV->setLinkage(GlobalValue::AvailableExternallyLinkage); + if (GV->hasComdat()) + NonPrevailingComdats.insert(GV->getComdat()); + 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,37 +607,75 @@ Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI, // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit. } + if (!M.getComdatSymbolTable().empty()) + for (GlobalValue &GV : M.global_values()) + handleNonPrevailingComdat(GV, NonPrevailingComdats); + assert(MsymI == MsymE); + return std::move(Mod); +} + +Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod, + bool LivenessFromIndex) { + if (!RegularLTO.CombinedModule) { + RegularLTO.CombinedModule = + llvm::make_unique<Module>("ld-temp.o", RegularLTO.Ctx); + RegularLTO.Mover = llvm::make_unique<IRMover>(*RegularLTO.CombinedModule); + } + + std::vector<GlobalValue *> Keep; + for (GlobalValue *GV : Mod.Keep) { + if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) + continue; - return RegularLTO.Mover->move(std::move(*MOrErr), Keep, + if (!GV->hasAvailableExternallyLinkage()) { + Keep.push_back(GV); + continue; + } + + // Only link available_externally definitions if we don't already have a + // definition. + GlobalValue *CombinedGV = + RegularLTO.CombinedModule->getNamedValue(GV->getName()); + if (CombinedGV && !CombinedGV->isDeclaration()) + continue; + + Keep.push_back(GV); + } + + return RegularLTO.Mover->move(std::move(Mod.M), 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, +// Add a ThinLTO module to the link. +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(); - ThinLTO.CombinedIndex.mergeFrom(std::move(*SummaryOrErr), - ThinLTO.ModuleMap.size()); + if (Error Err = + BM.readSummary(ThinLTO.CombinedIndex, BM.getModuleIdentifier(), + ThinLTO.ModuleMap.size())) + return Err; for (const InputFile::Symbol &Sym : Syms) { assert(ResI != ResE); SymbolResolution Res = *ResI++; - addSymbolToGlobalRes(Used, 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(); + + // For linker redefined symbols (via --wrap or --defsym) we want to + // switch the linkage to `weak` to prevent IPOs from happening. + // Find the summary in the module for this very GV and record the new + // linkage so that we can switch it when we import the GV. + if (Res.LinkerRedefined) + if (auto S = ThinLTO.CombinedIndex.findSummaryInModule( + GUID, BM.getModuleIdentifier())) + S->setLinkage(GlobalValue::WeakAnyLinkage); + } + } } if (!ThinLTO.ModuleMap.insert({BM.getModuleIdentifier(), BM}).second) @@ -533,10 +692,24 @@ unsigned LTO::getMaxTasks() const { } Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { + // Compute "dead" symbols, we don't want to import/export these! + DenseSet<GlobalValue::GUID> GUIDPreservedSymbols; + for (auto &Res : GlobalResolutions) { + if (Res.second.VisibleOutsideSummary && + // 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::dropLLVMManglingEscape(Res.second.IRName))); + } + + computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols); + // Save the status of having a regularLTO combined module, as // this is needed for generating the ThinLTO Task ID, and // the CombinedModule will be moved at the end of runRegularLTO. - bool HasRegularLTO = RegularLTO.CombinedModule != nullptr; + bool HasRegularLTO = RegularLTO.CombinedModule != nullptr || + !RegularLTO.ModsWithSummaries.empty(); // Invoke regular LTO if there was a regular LTO module to start with. if (HasRegularLTO) if (auto E = runRegularLTO(AddStream)) @@ -545,6 +718,11 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { } Error LTO::runRegularLTO(AddStreamFn AddStream) { + for (auto &M : RegularLTO.ModsWithSummaries) + if (Error Err = linkRegularLTO(std::move(M), + /*LivenessFromIndex=*/true)) + 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(); @@ -602,7 +780,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 +811,7 @@ class InProcessThinBackend : public ThinBackendProc { ThreadPool BackendThreadPool; AddStreamFn AddStream; NativeObjectCache Cache; + TypeIdSummariesByGuidTy TypeIdSummariesByGuid; Optional<Error> Err; std::mutex ErrMu; @@ -645,7 +824,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 +840,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 +864,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 +888,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 +901,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(); } @@ -842,7 +1030,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, // Collect for each module the list of function it defines (GUID -> // Summary). - StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> + StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries(ThinLTO.ModuleMap.size()); ThinLTO.CombinedIndex.collectDefinedGVSummariesPerModule( ModuleToDefinedGVSummaries); @@ -857,19 +1045,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( @@ -878,7 +1053,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, if (Conf.OptLevel > 0) { ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, - ImportLists, ExportLists, &DeadSymbols); + ImportLists, ExportLists); std::set<GlobalValue::GUID> ExportedGUIDs; for (auto &Res : GlobalResolutions) { @@ -890,16 +1065,13 @@ 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::dropLLVMManglingEscape(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)); + if (ThinLTO.CombinedIndex.isGUIDLive(GUID)) + ExportedGUIDs.insert(GUID); } - auto isPrevailing = [&](GlobalValue::GUID GUID, - const GlobalValueSummary *S) { - return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath(); - }; auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { const auto &ExportList = ExportLists.find(ModuleIdentifier); return (ExportList != ExportLists.end() && @@ -907,17 +1079,20 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, ExportedGUIDs.count(GUID); }; thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported); - - auto recordNewLinkage = [&](StringRef ModuleIdentifier, - GlobalValue::GUID GUID, - GlobalValue::LinkageTypes NewLinkage) { - ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; - }; - - thinLTOResolveWeakForLinkerInIndex(ThinLTO.CombinedIndex, isPrevailing, - recordNewLinkage); } + auto isPrevailing = [&](GlobalValue::GUID GUID, + const GlobalValueSummary *S) { + return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath(); + }; + auto recordNewLinkage = [&](StringRef ModuleIdentifier, + GlobalValue::GUID GUID, + GlobalValue::LinkageTypes NewLinkage) { + ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; + }; + thinLTOResolveWeakForLinkerInIndex(ThinLTO.CombinedIndex, isPrevailing, + recordNewLinkage); + std::unique_ptr<ThinBackendProc> BackendProc = ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, AddStream, Cache); @@ -937,3 +1112,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.setDiagnosticsHotnessRequested(true); + DiagnosticFile->keep(); + return std::move(DiagnosticFile); +} diff --git a/contrib/llvm/lib/LTO/LTOBackend.cpp b/contrib/llvm/lib/LTO/LTOBackend.cpp index 809db80..3f72e44 100644 --- a/contrib/llvm/lib/LTO/LTOBackend.cpp +++ b/contrib/llvm/lib/LTO/LTOBackend.cpp @@ -25,8 +25,8 @@ #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" #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" @@ -112,18 +112,79 @@ Error Config::addSaveTemps(std::string OutputFileName, namespace { std::unique_ptr<TargetMachine> -createTargetMachine(Config &Conf, StringRef TheTriple, - const Target *TheTarget) { +createTargetMachine(Config &Conf, const Target *TheTarget, Module &M) { + StringRef TheTriple = M.getTargetTriple(); SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(Triple(TheTriple)); for (const std::string &A : Conf.MAttrs) Features.AddFeature(A); + Reloc::Model RelocModel; + if (Conf.RelocModel) + RelocModel = *Conf.RelocModel; + else + RelocModel = + M.getPICLevel() == PICLevel::NotPIC ? Reloc::Static : Reloc::PIC_; + return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine( - TheTriple, Conf.CPU, Features.getString(), Conf.Options, Conf.RelocModel, + TheTriple, Conf.CPU, Features.getString(), Conf.Options, RelocModel, Conf.CodeModel, Conf.CGOptLevel)); } +static void runNewPMPasses(Module &Mod, TargetMachine *TM, unsigned OptLevel, + bool IsThinLTO) { + 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; + } + + if (IsThinLTO) + MPM = PB.buildThinLTODefaultPipeline(OL, false /* DebugLogging */); + else + 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 +229,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 +255,16 @@ 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) { + // 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 (Conf.UseNewPM) + runNewPMPasses(Mod, TM, Conf.OptLevel, IsThinLTO); + 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); } @@ -245,7 +312,7 @@ void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get()); std::unique_ptr<TargetMachine> TM = - createTargetMachine(C, MPartInCtx->getTargetTriple(), T); + createTargetMachine(C, T, *MPartInCtx); codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx); }, @@ -276,34 +343,40 @@ Expected<const Target *> initAndLookupTarget(Config &C, Module &Mod) { } -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(), - [&AsmUndefinedRefs](StringRef Name, object::BasicSymbolRef::Flags Flags) { - if (Flags & object::BasicSymbolRef::SF_Undefined) - AsmUndefinedRefs.insert(Name); - }); - updateCompilerUsed(Mod, TM, AsmUndefinedRefs); +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(); } 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(); - std::unique_ptr<TargetMachine> TM = - createTargetMachine(C, Mod->getTargetTriple(), *TOrErr); + std::unique_ptr<TargetMachine> TM = createTargetMachine(C, *TOrErr, *Mod); - handleAsmUndefinedRefs(*Mod, *TM); + // 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)) + 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 +384,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) { @@ -323,10 +397,7 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, if (!TOrErr) return TOrErr.takeError(); - std::unique_ptr<TargetMachine> TM = - createTargetMachine(Conf, Mod.getTargetTriple(), *TOrErr); - - handleAsmUndefinedRefs(Mod, *TM); + std::unique_ptr<TargetMachine> TM = createTargetMachine(Conf, *TOrErr, Mod); if (Conf.CodeGenOnly) { codegen(Conf, TM.get(), AddStream, Task, Mod); @@ -367,7 +438,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/contrib/llvm/lib/LTO/LTOCodeGenerator.cpp b/contrib/llvm/lib/LTO/LTOCodeGenerator.cpp index 6af31e6..6a27556 100644 --- a/contrib/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/contrib/llvm/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) { @@ -493,36 +495,14 @@ void LTOCodeGenerator::verifyMergedModuleOnce() { return; HasVerifiedInput = true; - if (LTOStripInvalidDebugInfo) { - bool BrokenDebugInfo = false; - if (verifyModule(*MergedModule, &dbgs(), &BrokenDebugInfo)) - report_fatal_error("Broken module found, compilation aborted!"); - if (BrokenDebugInfo) { - emitWarning("Invalid debug info found, debug info will be stripped"); - StripDebugInfo(*MergedModule); - } - } - if (verifyModule(*MergedModule, &dbgs())) + bool BrokenDebugInfo = false; + if (verifyModule(*MergedModule, &dbgs(), + LTOStripInvalidDebugInfo ? &BrokenDebugInfo : nullptr)) 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 (BrokenDebugInfo) { + emitWarning("Invalid debug info found, debug info will be stripped"); + StripDebugInfo(*MergedModule); } - - if (LTOPassRemarksWithHotness) - Context.setDiagnosticHotnessRequested(true); - - return true; } void LTOCodeGenerator::finishOptimizationRemarks() { @@ -540,8 +520,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 +552,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; @@ -610,6 +597,7 @@ bool LTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream *> Out) { // If statistics were requested, print them out after codegen. if (llvm::AreStatisticsEnabled()) llvm::PrintStatistics(); + reportAndResetTimings(); finishOptimizationRemarks(); diff --git a/contrib/llvm/lib/LTO/LTOModule.cpp b/contrib/llvm/lib/LTO/LTOModule.cpp index 89aeb80..3cc8b7d 100644 --- a/contrib/llvm/lib/LTO/LTOModule.cpp +++ b/contrib/llvm/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" @@ -76,14 +77,12 @@ bool LTOModule::isBitcodeFile(StringRef Path) { } bool LTOModule::isThinLTO() { - // Right now the detection is only based on the summary presence. We may want - // to add a dedicated flag at some point. - Expected<bool> Result = hasGlobalValueSummary(MBRef); + Expected<BitcodeLTOInfo> Result = getBitcodeLTOInfo(MBRef); if (!Result) { logAllUnhandledErrors(Result.takeError(), errs(), ""); return false; } - return *Result; + return Result->IsThinLTO; } bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer, @@ -636,10 +635,10 @@ void LTOModule::parseMetadata() { raw_string_ostream OS(LinkerOpts); // Linker Options - if (Metadata *Val = getModule().getModuleFlag("Linker Options")) { - MDNode *LinkerOptions = cast<MDNode>(Val); + if (NamedMDNode *LinkerOptions = + getModule().getNamedMetadata("llvm.linker.options")) { for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) { - MDNode *MDOptions = cast<MDNode>(LinkerOptions->getOperand(i)); + MDNode *MDOptions = LinkerOptions->getOperand(i); for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) { MDString *MDOption = cast<MDString>(MDOptions->getOperand(ii)); OS << " " << MDOption->getString(); @@ -647,11 +646,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/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp index 40537e4..1efd481 100644 --- a/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/contrib/llvm/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" @@ -28,16 +24,16 @@ #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/ExecutionEngine/ObjectMemoryBuffer.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" +#include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/LTO/LTO.h" -#include "llvm/Linker/Linker.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/IRObjectFile.h" -#include "llvm/Object/ModuleSummaryIndexObjectFile.h" #include "llvm/Support/CachePruning.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.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" @@ -66,6 +63,7 @@ namespace llvm { extern cl::opt<bool> LTODiscardValueNames; extern cl::opt<std::string> LTORemarksFilename; extern cl::opt<bool> LTOPassRemarksWithHotness; +extern cl::opt<bool> LTOStripInvalidDebugInfo; } namespace { @@ -73,27 +71,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) { @@ -144,8 +121,9 @@ static void computePrevailingCopies( }; for (auto &I : Index) { - if (HasMultipleCopies(I.second)) - PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second); + if (HasMultipleCopies(I.second.SummaryList)) + PrevailingCopy[I.first] = + getFirstDefinitionForLinker(I.second.SummaryList); } } @@ -166,6 +144,30 @@ static void promoteModule(Module &TheModule, const ModuleSummaryIndex &Index) { report_fatal_error("renameModuleForThinLTO failed"); } +namespace { +class ThinLTODiagnosticInfo : public DiagnosticInfo { + const Twine &Msg; +public: + ThinLTODiagnosticInfo(const Twine &DiagMsg, + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {} + void print(DiagnosticPrinter &DP) const override { DP << Msg; } +}; +} + +/// Verify the module and strip broken debug info. +static void verifyLoadedModule(Module &TheModule) { + bool BrokenDebugInfo = false; + if (verifyModule(TheModule, &dbgs(), + LTOStripInvalidDebugInfo ? &BrokenDebugInfo : nullptr)) + report_fatal_error("Broken module found, compilation aborted!"); + if (BrokenDebugInfo) { + TheModule.getContext().diagnose(ThinLTODiagnosticInfo( + "Invalid debug info found, debug info will be stripped", DS_Warning)); + StripDebugInfo(TheModule); + } +} + static std::unique_ptr<Module> loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context, bool Lazy, bool IsImporting) { @@ -183,6 +185,8 @@ loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context, }); report_fatal_error("Can't load module, abort."); } + if (!Lazy) + verifyLoadedModule(*ModuleOrErr.get()); return std::move(ModuleOrErr.get()); } @@ -205,19 +209,24 @@ crossImportIntoModule(Module &TheModule, const ModuleSummaryIndex &Index, }); report_fatal_error("importFunctions failed"); } + // Verify again after cross-importing. + verifyLoadedModule(TheModule); } 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; PMB.LoopVectorize = true; PMB.SLPVectorize = true; - PMB.VerifyInput = true; + // Already did this in verifyLoadedModule(). + PMB.VerifyInput = false; PMB.VerifyOutput = false; legacy::PassManager PM; @@ -285,7 +294,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 +332,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 +351,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 +379,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 +435,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 +467,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"); @@ -464,7 +477,7 @@ ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index, { raw_svector_ostream OS(OutputBuffer); ProfileSummaryInfo PSI(TheModule); - auto Index = buildModuleSummaryIndex(TheModule, nullptr, nullptr); + auto Index = buildModuleSummaryIndex(TheModule, nullptr, &PSI); WriteBitcodeToFile(&TheModule, OS, true, &Index); } return make_unique<ObjectMemoryBuffer>(std::move(OutputBuffer)); @@ -523,29 +536,25 @@ static void initTMBuilder(TargetMachineBuilder &TMBuilder, void ThinLTOCodeGenerator::addModule(StringRef Identifier, StringRef Data) { ThinLTOBuffer Buffer(Data, Identifier); - if (Modules.empty()) { - // First module added, so initialize the triple and some options - LLVMContext Context; - StringRef TripleStr; - ErrorOr<std::string> TripleOrErr = expectedToErrorOrAndEmitErrors( - Context, getBitcodeTargetTriple(Buffer.getMemBuffer())); - if (TripleOrErr) - TripleStr = *TripleOrErr; - Triple TheTriple(TripleStr); + LLVMContext Context; + StringRef TripleStr; + ErrorOr<std::string> TripleOrErr = expectedToErrorOrAndEmitErrors( + Context, getBitcodeTargetTriple(Buffer.getMemBuffer())); + + if (TripleOrErr) + TripleStr = *TripleOrErr; + + Triple TheTriple(TripleStr); + + if (Modules.empty()) initTMBuilder(TMBuilder, Triple(TheTriple)); + else if (TMBuilder.TheTriple != TheTriple) { + if (!TMBuilder.TheTriple.isCompatibleWith(TheTriple)) + report_fatal_error("ThinLTO modules with incompatible triples not " + "supported"); + initTMBuilder(TMBuilder, Triple(TMBuilder.TheTriple.merge(TheTriple))); } -#ifndef NDEBUG - else { - LLVMContext Context; - StringRef TripleStr; - ErrorOr<std::string> TripleOrErr = expectedToErrorOrAndEmitErrors( - Context, getBitcodeTargetTriple(Buffer.getMemBuffer())); - if (TripleOrErr) - TripleStr = *TripleOrErr; - assert(TMBuilder.TheTriple.str() == TripleStr && - "ThinLTO modules with different triple not supported"); - } -#endif + Modules.push_back(Buffer); } @@ -584,25 +593,18 @@ std::unique_ptr<TargetMachine> TargetMachineBuilder::create() const { * "thin-link". */ std::unique_ptr<ModuleSummaryIndex> ThinLTOCodeGenerator::linkCombinedIndex() { - std::unique_ptr<ModuleSummaryIndex> CombinedIndex; + std::unique_ptr<ModuleSummaryIndex> CombinedIndex = + llvm::make_unique<ModuleSummaryIndex>(); uint64_t NextModuleId = 0; for (auto &ModuleBuffer : Modules) { - Expected<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr = - object::ModuleSummaryIndexObjectFile::create( - ModuleBuffer.getMemBuffer()); - if (!ObjOrErr) { + if (Error Err = readModuleSummaryIndex(ModuleBuffer.getMemBuffer(), + *CombinedIndex, NextModuleId++)) { // FIXME diagnose logAllUnhandledErrors( - ObjOrErr.takeError(), errs(), - "error: can't create ModuleSummaryIndexObjectFile for buffer: "); + std::move(Err), errs(), + "error: can't create module summary index for buffer: "); return nullptr; } - auto Index = (*ObjOrErr)->takeIndex(); - if (CombinedIndex) { - CombinedIndex->mergeFrom(std::move(Index), ++NextModuleId); - } else { - CombinedIndex = std::move(Index); - } } return CombinedIndex; } @@ -625,13 +627,13 @@ void ThinLTOCodeGenerator::promote(Module &TheModule, PreservedSymbols, Triple(TheModule.getTargetTriple())); // Compute "dead" symbols, we don't want to import/export these! - auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols); + computeDeadSymbols(Index, GUIDPreservedSymbols); // Generate import/export list StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount); StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount); ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists, - ExportLists, &DeadSymbols); + ExportLists); // Resolve LinkOnce/Weak symbols. StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; @@ -670,13 +672,13 @@ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule, PreservedSymbols, Triple(TheModule.getTargetTriple())); // Compute "dead" symbols, we don't want to import/export these! - auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols); + computeDeadSymbols(Index, GUIDPreservedSymbols); // Generate import/export list StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount); StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount); ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists, - ExportLists, &DeadSymbols); + ExportLists); auto &ImportList = ImportLists[TheModule.getModuleIdentifier()]; crossImportIntoModule(TheModule, Index, ModuleMap, ImportList); @@ -747,13 +749,13 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule, Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); // Compute "dead" symbols, we don't want to import/export these! - auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols); + computeDeadSymbols(Index, GUIDPreservedSymbols); // Generate import/export list StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount); StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount); ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists, - ExportLists, &DeadSymbols); + ExportLists); auto &ExportList = ExportLists[ModuleIdentifier]; // Be friendly and don't nuke totally the module when the client didn't @@ -780,7 +782,7 @@ void ThinLTOCodeGenerator::optimize(Module &TheModule) { initTMBuilder(TMBuilder, Triple(TheModule.getTargetTriple())); // Optimize now - optimizeModule(TheModule, *TMBuilder.create(), OptLevel); + optimizeModule(TheModule, *TMBuilder.create(), OptLevel, Freestanding); } /** @@ -899,14 +901,14 @@ void ThinLTOCodeGenerator::run() { computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple); // Compute "dead" symbols, we don't want to import/export these! - auto DeadSymbols = computeDeadSymbols(*Index, GUIDPreservedSymbols); + computeDeadSymbols(*Index, GUIDPreservedSymbols); // Collect the import/export lists for all modules from the call-graph in the // combined index. StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount); StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount); ComputeCrossModuleImport(*Index, ModuleToDefinedGVSummaries, ImportLists, - ExportLists, &DeadSymbols); + ExportLists); // We use a std::map here to be able to have a defined ordering when // producing a hash for the cache entry. @@ -966,7 +968,7 @@ void ThinLTOCodeGenerator::run() { ImportLists[ModuleIdentifier], ExportList, ResolvedODR[ModuleIdentifier], DefinedFunctions, GUIDPreservedSymbols, - OptLevel, TMBuilder); + OptLevel, Freestanding, TMBuilder); auto CacheEntryPath = CacheEntry.getEntryPath(); { @@ -990,7 +992,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 +1014,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,13 +1046,10 @@ 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()) llvm::PrintStatistics(); + reportAndResetTimings(); } diff --git a/contrib/llvm/lib/LTO/UpdateCompilerUsed.cpp b/contrib/llvm/lib/LTO/UpdateCompilerUsed.cpp index b67d9ea..5165cc9 100644 --- a/contrib/llvm/lib/LTO/UpdateCompilerUsed.cpp +++ b/contrib/llvm/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)); } |