Index: include/llvm/LTO/legacy/ThinLTOCodeGenerator.h =================================================================== --- include/llvm/LTO/legacy/ThinLTOCodeGenerator.h +++ include/llvm/LTO/legacy/ThinLTOCodeGenerator.h @@ -28,8 +28,11 @@ namespace llvm { class StringRef; -class LLVMContext; class TargetMachine; +namespace lto { +struct Config; +class LTO; +} /// Helper to gather options relevant to the target machine creation struct TargetMachineBuilder { @@ -202,7 +205,7 @@ * and additionally resolve weak and linkonce symbols. * Index is updated to reflect linkage changes from weak resolution. */ - void promote(Module &Module, ModuleSummaryIndex &Index); + void promote(std::function Callback); /** * Compute and emit the imported files for module at \p ModulePath. @@ -214,7 +217,8 @@ * Perform cross-module importing for the module identified by * ModuleIdentifier. */ - void crossModuleImport(Module &Module, ModuleSummaryIndex &Index); + void + crossModuleImport(std::function Callback); /** * Compute the list of summaries needed for importing into module. @@ -226,7 +230,7 @@ /** * Perform internalization. Index is updated to reflect linkage changes. */ - void internalize(Module &Module, ModuleSummaryIndex &Index); + void internalize(std::function); /** * Perform post-importing ThinLTO optimizations. @@ -241,6 +245,17 @@ /**@}*/ private: + /// Build the configuration for the LTO API + lto::Config getLTOConfig(); + + /// Go through the objects, build the resolutions, and add these to the LTO + /// Code Generator. + void populateCodeGenerator(lto::LTO &Codegen); + + /// Run the LTO pipeline using the supplied configuration. This private method + /// is used by individual steps (internalize, promote, ...). + void runWithConfig(lto::Config Conf); + /// Helper factory to build a TargetMachine TargetMachineBuilder TMBuilder; Index: lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- lib/LTO/ThinLTOCodeGenerator.cpp +++ lib/LTO/ThinLTOCodeGenerator.cpp @@ -31,6 +31,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IRReader/IRReader.h" +#include "llvm/LTO/Caching.h" #include "llvm/LTO/LTO.h" #include "llvm/Linker/Linker.h" #include "llvm/MC/SubtargetFeature.h" @@ -56,11 +57,6 @@ #define DEBUG_TYPE "thinlto" -namespace llvm { -// Flags -discard-value-names, defined in LTOCodeGenerator.cpp -extern cl::opt LTODiscardValueNames; -} - namespace { static cl::opt ThreadCount("threads", @@ -72,87 +68,6 @@ errs() << '\n'; } -// Simple helper to save temporary files for debug. -static void saveTempBitcode(const Module &TheModule, StringRef TempDir, - unsigned count, StringRef Suffix) { - if (TempDir.empty()) - return; - // User asked to save temps, let dump the bitcode file after import. - std::string SaveTempPath = (TempDir + llvm::utostr(count) + Suffix).str(); - std::error_code EC; - raw_fd_ostream OS(SaveTempPath, EC, sys::fs::F_None); - if (EC) - report_fatal_error(Twine("Failed to open ") + SaveTempPath + - " to save optimized bitcode\n"); - WriteBitcodeToFile(&TheModule, OS, /* ShouldPreserveUseListOrder */ true); -} - -static const GlobalValueSummary * -getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) { - // If there is any strong definition anywhere, get it. - auto StrongDefForLinker = llvm::find_if( - GVSummaryList, [](const std::unique_ptr &Summary) { - auto Linkage = Summary->linkage(); - return !GlobalValue::isAvailableExternallyLinkage(Linkage) && - !GlobalValue::isWeakForLinker(Linkage); - }); - if (StrongDefForLinker != GVSummaryList.end()) - return StrongDefForLinker->get(); - // Get the first *linker visible* definition for this global in the summary - // list. - auto FirstDefForLinker = llvm::find_if( - GVSummaryList, [](const std::unique_ptr &Summary) { - auto Linkage = Summary->linkage(); - return !GlobalValue::isAvailableExternallyLinkage(Linkage); - }); - // Extern templates can be emitted as available_externally. - if (FirstDefForLinker == GVSummaryList.end()) - return nullptr; - return FirstDefForLinker->get(); -} - -// Populate map of GUID to the prevailing copy for any multiply defined -// symbols. Currently assume first copy is prevailing, or any strong -// definition. Can be refined with Linker information in the future. -static void computePrevailingCopies( - const ModuleSummaryIndex &Index, - DenseMap &PrevailingCopy) { - auto HasMultipleCopies = [&](const GlobalValueSummaryList &GVSummaryList) { - return GVSummaryList.size() > 1; - }; - - for (auto &I : Index) { - if (HasMultipleCopies(I.second)) - PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second); - } -} - -static StringMap -generateModuleMap(const std::vector &Modules) { - StringMap ModuleMap; - for (auto &ModuleBuffer : Modules) { - assert(ModuleMap.find(ModuleBuffer.getBufferIdentifier()) == - ModuleMap.end() && - "Expect unique Buffer Identifier"); - ModuleMap[ModuleBuffer.getBufferIdentifier()] = ModuleBuffer; - } - return ModuleMap; -} - -static void promoteModule(Module &TheModule, const ModuleSummaryIndex &Index) { - if (renameModuleForThinLTO(TheModule, Index)) - report_fatal_error("renameModuleForThinLTO failed"); -} - -static void -crossImportIntoModule(Module &TheModule, const ModuleSummaryIndex &Index, - StringMap &ModuleMap, - const FunctionImporter::ImportMapTy &ImportList) { - ModuleLoader Loader(TheModule.getContext(), ModuleMap); - FunctionImporter Importer(Index, Loader); - Importer.importFunctions(TheModule, ImportList); -} - static void optimizeModule(Module &TheModule, TargetMachine &TM) { // Populate the PassManager PassManagerBuilder PMB; @@ -177,20 +92,6 @@ PM.run(TheModule); } -// Convert the PreservedSymbols map from "Name" based to "GUID" based. -static DenseSet -computeGUIDPreservedSymbols(const StringSet<> &PreservedSymbols, - const Triple &TheTriple) { - DenseSet GUIDPreservedSymbols(PreservedSymbols.size()); - for (auto &Entry : PreservedSymbols) { - StringRef Name = Entry.first(); - if (TheTriple.isOSBinFormatMachO() && Name.size() > 0 && Name[0] == '_') - Name = Name.drop_front(); - GUIDPreservedSymbols.insert(GlobalValue::getGUID(Name)); - } - return GUIDPreservedSymbols; -} - std::unique_ptr codegenModule(Module &TheModule, TargetMachine &TM) { SmallVector OutputBuffer; @@ -215,207 +116,6 @@ return make_unique(std::move(OutputBuffer)); } -/// Manage caching for a single Module. -class ModuleCacheEntry { - SmallString<128> EntryPath; - -public: - // Create a cache entry. This compute a unique hash for the Module considering - // the current list of export/import, and offer an interface to query to - // access the content in the cache. - ModuleCacheEntry( - StringRef CachePath, const ModuleSummaryIndex &Index, StringRef ModuleID, - const FunctionImporter::ImportMapTy &ImportList, - const FunctionImporter::ExportSetTy &ExportList, - const std::map &ResolvedODR, - const GVSummaryMapTy &DefinedFunctions, - const DenseSet &PreservedSymbols) { - if (CachePath.empty()) - return; - - // 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 - // list of ResolvedODR for the module, and the list of preserved symbols. - - SHA1 Hasher; - - // Start with the compiler revision - Hasher.update(LLVM_VERSION_STRING); -#ifdef HAVE_LLVM_REVISION - Hasher.update(LLVM_REVISION); -#endif - - // Include the hash for the current module - auto ModHash = Index.getModuleHash(ModuleID); - Hasher.update(ArrayRef((uint8_t *)&ModHash[0], sizeof(ModHash))); - for (auto F : ExportList) - // The export list can impact the internalization, be conservative here - Hasher.update(ArrayRef((uint8_t *)&F, sizeof(F))); - - // Include the hash for every module we import functions from - for (auto &Entry : ImportList) { - auto ModHash = Index.getModuleHash(Entry.first()); - Hasher.update(ArrayRef((uint8_t *)&ModHash[0], sizeof(ModHash))); - } - - // Include the hash for the resolved ODR. - for (auto &Entry : ResolvedODR) { - Hasher.update(ArrayRef((const uint8_t *)&Entry.first, - sizeof(GlobalValue::GUID))); - Hasher.update(ArrayRef((const uint8_t *)&Entry.second, - sizeof(GlobalValue::LinkageTypes))); - } - - // Include the hash for the preserved symbols. - for (auto &Entry : PreservedSymbols) { - if (DefinedFunctions.count(Entry)) - Hasher.update( - ArrayRef((const uint8_t *)&Entry, sizeof(GlobalValue::GUID))); - } - - sys::path::append(EntryPath, CachePath, toHex(Hasher.result())); - } - - // Access the path to this entry in the cache. - StringRef getEntryPath() { return EntryPath; } - - // Try loading the buffer for this cache entry. - ErrorOr> tryLoadingBuffer() { - if (EntryPath.empty()) - return std::error_code(); - return MemoryBuffer::getFile(EntryPath); - } - - // Cache the Produced object file - std::unique_ptr - write(std::unique_ptr OutputBuffer) { - if (EntryPath.empty()) - return OutputBuffer; - - // Write to a temporary to avoid race condition - SmallString<128> TempFilename; - int TempFD; - std::error_code EC = - sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename); - if (EC) { - errs() << "Error: " << EC.message() << "\n"; - report_fatal_error("ThinLTO: Can't get a temporary file"); - } - { - raw_fd_ostream OS(TempFD, /* ShouldClose */ true); - OS << OutputBuffer->getBuffer(); - } - // Rename to final destination (hopefully race condition won't matter here) - EC = sys::fs::rename(TempFilename, EntryPath); - if (EC) { - sys::fs::remove(TempFilename); - 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"); - OS << OutputBuffer->getBuffer(); - } - auto ReloadedBufferOrErr = MemoryBuffer::getFile(EntryPath); - if (auto EC = ReloadedBufferOrErr.getError()) { - // FIXME diagnose - errs() << "error: can't reload cached file '" << EntryPath - << "': " << EC.message() << "\n"; - return OutputBuffer; - } - return std::move(*ReloadedBufferOrErr); - } -}; - -static std::unique_ptr -ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index, - StringMap &ModuleMap, TargetMachine &TM, - const FunctionImporter::ImportMapTy &ImportList, - const FunctionImporter::ExportSetTy &ExportList, - const DenseSet &GUIDPreservedSymbols, - const GVSummaryMapTy &DefinedGlobals, - const ThinLTOCodeGenerator::CachingOptions &CacheOptions, - bool DisableCodeGen, StringRef SaveTempsDir, - unsigned count) { - - // "Benchmark"-like optimization: single-source case - bool SingleModule = (ModuleMap.size() == 1); - - if (!SingleModule) { - promoteModule(TheModule, Index); - - // Apply summary-based LinkOnce/Weak resolution decisions. - thinLTOResolveWeakForLinkerModule(TheModule, DefinedGlobals); - - // Save temps: after promotion. - saveTempBitcode(TheModule, SaveTempsDir, count, ".1.promoted.bc"); - } - - // Be friendly and don't nuke totally the module when the client didn't - // supply anything to preserve. - if (!ExportList.empty() || !GUIDPreservedSymbols.empty()) { - // Apply summary-based internalization decisions. - thinLTOInternalizeModule(TheModule, DefinedGlobals); - } - - // Save internalized bitcode - saveTempBitcode(TheModule, SaveTempsDir, count, ".2.internalized.bc"); - - if (!SingleModule) { - crossImportIntoModule(TheModule, Index, ModuleMap, ImportList); - - // Save temps: after cross-module import. - saveTempBitcode(TheModule, SaveTempsDir, count, ".3.imported.bc"); - } - - optimizeModule(TheModule, TM); - - saveTempBitcode(TheModule, SaveTempsDir, count, ".4.opt.bc"); - - if (DisableCodeGen) { - // Configured to stop before CodeGen, serialize the bitcode and return. - SmallVector OutputBuffer; - { - raw_svector_ostream OS(OutputBuffer); - auto Index = buildModuleSummaryIndex(TheModule); - WriteBitcodeToFile(&TheModule, OS, true, &Index); - } - return make_unique(std::move(OutputBuffer)); - } - - return codegenModule(TheModule, TM); -} - -/// Resolve LinkOnce/Weak symbols. Record resolutions in the \p ResolvedODR map -/// for caching, and in the \p Index for application during the ThinLTO -/// backends. This is needed for correctness for exported symbols (ensure -/// at least one copy kept) and a compile-time optimization (to drop duplicate -/// copies when possible). -static void resolveWeakForLinkerInIndex( - ModuleSummaryIndex &Index, - StringMap> - &ResolvedODR) { - - DenseMap PrevailingCopy; - computePrevailingCopies(Index, PrevailingCopy); - - auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) { - const auto &Prevailing = PrevailingCopy.find(GUID); - // Not in map means that there was only one copy, which must be prevailing. - if (Prevailing == PrevailingCopy.end()) - return true; - return Prevailing->second == S; - }; - - auto recordNewLinkage = [&](StringRef ModuleIdentifier, - GlobalValue::GUID GUID, - GlobalValue::LinkageTypes NewLinkage) { - ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; - }; - - thinLTOResolveWeakForLinkerInIndex(Index, isPrevailing, recordNewLinkage); -} - // Initialize the TargetMachine builder for a given Triple static void initTMBuilder(TargetMachineBuilder &TMBuilder, const Triple &TheTriple) { @@ -513,64 +213,35 @@ * Perform promotion and renaming of exported internal functions. * Index is updated to reflect linkage changes from weak resolution. */ -void ThinLTOCodeGenerator::promote(Module &TheModule, - ModuleSummaryIndex &Index) { - auto ModuleCount = Index.modulePaths().size(); - auto ModuleIdentifier = TheModule.getModuleIdentifier(); - // Collect for each module the list of function it defines (GUID -> Summary). - StringMap ModuleToDefinedGVSummaries; - Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); - - // Convert the preserved symbols set from string to GUID - auto GUIDPreservedSymbols = computeGUIDPreservedSymbols( - PreservedSymbols, Triple(TheModule.getTargetTriple())); - - // Compute "dead" symbols, we don't want to import/export these! - auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols); - - // Generate import/export list - StringMap ImportLists(ModuleCount); - StringMap ExportLists(ModuleCount); - ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists, - ExportLists, &DeadSymbols); - - // Resolve LinkOnce/Weak symbols. - StringMap> ResolvedODR; - resolveWeakForLinkerInIndex(Index, ResolvedODR); - - thinLTOResolveWeakForLinkerModule( - TheModule, ModuleToDefinedGVSummaries[ModuleIdentifier]); +void ThinLTOCodeGenerator::promote( + std::function Callback) { + // Initial configuration + auto Conf = getLTOConfig(); + + // Setup the client hook. + Conf.PostPromoteModuleHook = [&](unsigned Task, const Module &M) { + Callback(Task, M); + return false; + }; - promoteModule(TheModule, Index); + runWithConfig(std::move(Conf)); } /** * Perform cross-module importing for the module identified by ModuleIdentifier. */ -void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule, - ModuleSummaryIndex &Index) { - auto ModuleMap = generateModuleMap(Modules); - auto ModuleCount = Index.modulePaths().size(); - - // Collect for each module the list of function it defines (GUID -> Summary). - StringMap ModuleToDefinedGVSummaries(ModuleCount); - Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); - - // Convert the preserved symbols set from string to GUID - auto GUIDPreservedSymbols = computeGUIDPreservedSymbols( - PreservedSymbols, Triple(TheModule.getTargetTriple())); - - // Compute "dead" symbols, we don't want to import/export these! - auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols); - - // Generate import/export list - StringMap ImportLists(ModuleCount); - StringMap ExportLists(ModuleCount); - ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists, - ExportLists, &DeadSymbols); - auto &ImportList = ImportLists[TheModule.getModuleIdentifier()]; +void ThinLTOCodeGenerator::crossModuleImport( + std::function Callback) { + // Initial configuration + auto Conf = getLTOConfig(); + + // Setup the client hook. + Conf.PostImportModuleHook = [&](unsigned Task, const Module &M) { + Callback(Task, M); + return false; + }; - crossImportIntoModule(TheModule, Index, ModuleMap, ImportList); + runWithConfig(std::move(Conf)); } /** @@ -623,45 +294,18 @@ /** * Perform internalization. Index is updated to reflect linkage changes. */ -void ThinLTOCodeGenerator::internalize(Module &TheModule, - ModuleSummaryIndex &Index) { - initTMBuilder(TMBuilder, Triple(TheModule.getTargetTriple())); - auto ModuleCount = Index.modulePaths().size(); - auto ModuleIdentifier = TheModule.getModuleIdentifier(); - - // Convert the preserved symbols set from string to GUID - auto GUIDPreservedSymbols = - computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple); - - // Collect for each module the list of function it defines (GUID -> Summary). - StringMap ModuleToDefinedGVSummaries(ModuleCount); - Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); - - // Compute "dead" symbols, we don't want to import/export these! - auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols); - - // Generate import/export list - StringMap ImportLists(ModuleCount); - StringMap ExportLists(ModuleCount); - ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists, - ExportLists, &DeadSymbols); - auto &ExportList = ExportLists[ModuleIdentifier]; - - // Be friendly and don't nuke totally the module when the client didn't - // supply anything to preserve. - if (ExportList.empty() && GUIDPreservedSymbols.empty()) - return; - - // Internalization - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); +void ThinLTOCodeGenerator::internalize( + std::function Callback) { + // Initial configuration + auto Conf = getLTOConfig(); + + // Setup the client hook. + Conf.PostInternalizeModuleHook = [&](unsigned Task, const Module &M) { + Callback(Task, M); + return false; }; - thinLTOInternalizeAndPromoteInIndex(Index, isExported); - thinLTOInternalizeModule(TheModule, - ModuleToDefinedGVSummaries[ModuleIdentifier]); + + runWithConfig(std::move(Conf)); } /** @@ -682,167 +326,203 @@ return codegenModule(TheModule, *TMBuilder.create()); } -// Main entry point for the ThinLTO processing -void ThinLTOCodeGenerator::run() { - if (CodeGenOnly) { - // Perform only parallel codegen and return. - ThreadPool Pool; - assert(ProducedBinaries.empty() && "The generator should not be reused"); - ProducedBinaries.resize(Modules.size()); - int count = 0; - for (auto &ModuleBuffer : Modules) { - Pool.async([&](int count) { - LLVMContext Context; - Context.setDiscardValueNames(LTODiscardValueNames); - - // Parse module now - auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false); - - // CodeGen - ProducedBinaries[count] = codegen(*TheModule); - }, count++); - } +namespace { +// Define the LTOOutput handling +class LTOOutput : public lto::NativeObjectOutput { + SmallVector OutputBuffer; + std::unique_ptr &Output; - return; +public: + LTOOutput(std::unique_ptr &Output) : Output(Output) {} + ~LTOOutput() { + Output = make_unique(std::move(OutputBuffer)); } - - // Sequential linking phase - auto Index = linkCombinedIndex(); - - // Save temps: index. - if (!SaveTempsDir.empty()) { - auto SaveTempPath = SaveTempsDir + "index.bc"; - std::error_code EC; - raw_fd_ostream OS(SaveTempPath, EC, sys::fs::F_None); - if (EC) - report_fatal_error(Twine("Failed to open ") + SaveTempPath + - " to save optimized bitcode\n"); - WriteIndexToFile(*Index, OS); + std::unique_ptr getStream() override { + return make_unique(OutputBuffer); } +}; +} - // Prepare the resulting object vector - assert(ProducedBinaries.empty() && "The generator should not be reused"); - ProducedBinaries.resize(Modules.size()); - - // Prepare the module map. - auto ModuleMap = generateModuleMap(Modules); - auto ModuleCount = Modules.size(); - - // Collect for each module the list of function it defines (GUID -> Summary). - StringMap ModuleToDefinedGVSummaries(ModuleCount); - Index->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); +void ThinLTOCodeGenerator::runWithConfig(lto::Config Conf) { + // Create the code generator + lto::ThinBackend Backend = lto::createInProcessThinBackend(ThreadCount); + lto::LTO Codegen(std::move(Conf), Backend); + + // Add inputs to the CodeGenerator and get it ready for processing. + populateCodeGenerator(Codegen); + + // We have no guarantee that all Tasks will feed an output buffer. So we use + // an intermediate vector to store each possible output. + std::vector> OutputBuffers; + OutputBuffers.resize(Codegen.getMaxTasks()); + // Callback for the LTO API. + auto AddOutput = + [&](unsigned Task) -> std::unique_ptr { + struct AssertingLTOOuput : public lto::NativeObjectOutput { + std::unique_ptr getStream() override { + report_fatal_error("Unexpected"); + } + }; + return make_unique(); + }; - // Convert the preserved symbols set from string to GUID, this is needed for - // computing the caching hash and the internalization. - auto GUIDPreservedSymbols = - computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple); + // Run the actual optimizations/codegen now. + auto Err = Codegen.run(AddOutput); + if (Err) + report_fatal_error("FATAL: Codegen.run error: " + toString(std::move(Err))); +} - // Compute "dead" symbols, we don't want to import/export these! - auto DeadSymbols = computeDeadSymbols(*Index, GUIDPreservedSymbols); +lto::Config ThinLTOCodeGenerator::getLTOConfig() { + lto::Config Conf; + // Initialize the LTO options + Conf.DiagHandler = diagnosticHandler; + Conf.CPU = TMBuilder.MCpu; + Conf.Options = TMBuilder.Options; + StringRef MAttrs = TMBuilder.MAttr; + while (!MAttrs.empty()) { + StringRef MAttr; + std::tie(MAttr, MAttrs) = MAttrs.split(","); + Conf.MAttrs.push_back(MAttr); + } + if (TMBuilder.RelocModel) + Conf.RelocModel = *TMBuilder.RelocModel; + Conf.CGOptLevel = TMBuilder.CGOptLevel; + Conf.DisableVerify = true; + Conf.OptLevel = 3; // FIXME parameter... + Conf.CodeGenOnly = CodeGenOnly; + + if (!SaveTempsDir.empty()) + if (auto EC = Conf.addSaveTemps(SaveTempsDir)) + report_fatal_error("Can add save temps dir"); + + return Conf; +} - // Collect the import/export lists for all modules from the call-graph in the - // combined index. - StringMap ImportLists(ModuleCount); - StringMap ExportLists(ModuleCount); - ComputeCrossModuleImport(*Index, ModuleToDefinedGVSummaries, ImportLists, - ExportLists, &DeadSymbols); - - // We use a std::map here to be able to have a defined ordering when - // producing a hash for the cache entry. - // FIXME: we should be able to compute the caching hash for the entry based - // on the index, and nuke this map. - StringMap> ResolvedODR; - - // Resolve LinkOnce/Weak symbols, this has to be computed early because it - // impacts the caching. - resolveWeakForLinkerInIndex(*Index, ResolvedODR); - - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); - }; +void ThinLTOCodeGenerator::populateCodeGenerator(lto::LTO &Codegen) { + // Perform symbol resolution first, preparing all the lto::Input to feed to + // the LTO API. + std::vector> Inputs; + Inputs.reserve(Modules.size()); - // Use global summary-based analysis to identify symbols that can be - // internalized (because they aren't exported or preserved as per callback). - // Changes are made in the index, consumed in the ThinLTO backends. - thinLTOInternalizeAndPromoteInIndex(*Index, isExported); + // Keep a map from symbol name to the input that defines it. + StringMap> PrevailingSymbols; - // Make sure that every module has an entry in the ExportLists and - // ResolvedODR maps to enable threaded access to these maps below. - for (auto &DefinedGVSummaries : ModuleToDefinedGVSummaries) { - ExportLists[DefinedGVSummaries.first()]; - ResolvedODR[DefinedGVSummaries.first()]; + // First create all the InputFile and go through all the symbols, keeping + // track of prevailing copies. + for (auto &ModuleBuffer : Modules) { + auto InputOrErr = lto::InputFile::create(ModuleBuffer); + if (!InputOrErr) + report_fatal_error("Can't load input? '" + + ModuleBuffer.getBufferIdentifier() + "'"); + std::unique_ptr Input = std::move(*InputOrErr); + // Iterate symbols in the input file. We only gets global symbol here, so + // the only logic we need is to mark prevailing the first copy of a weak + // symbol. + for (const lto::InputFile::Symbol &Sym : Input->symbols()) { + if (Sym.getName().empty()) + report_fatal_error("Unexpected Unnamed LTO symbol"); + + if (!(Sym.getFlags() & object::BasicSymbolRef::SF_Undefined)) { + auto &Entry = PrevailingSymbols[Sym.getName()]; + if (Entry.first && !Entry.second && + !(Sym.getFlags() & (object::BasicSymbolRef::SF_Weak | + object::BasicSymbolRef::SF_Common))) + // Non-weak duplicate symbol definitions are not allowed + report_fatal_error(Twine("Duplicated symbol:") + Sym.getName()); + if (!Entry.first) { + Entry.first = Input.get(); + Entry.second = (Sym.getFlags() & (object::BasicSymbolRef::SF_Weak | + object::BasicSymbolRef::SF_Common)); + } + } + } + Inputs.push_back(std::move(Input)); } - // Compute the ordering we will process the inputs: the rough heuristic here - // is to sort them per size so that the largest module get schedule as soon as - // possible. This is purely a compile-time optimization. - std::vector ModulesOrdering; - ModulesOrdering.resize(Modules.size()); - std::iota(ModulesOrdering.begin(), ModulesOrdering.end(), 0); - std::sort(ModulesOrdering.begin(), ModulesOrdering.end(), - [&](int LeftIndex, int RightIndex) { - auto LSize = Modules[LeftIndex].getBufferSize(); - auto RSize = Modules[RightIndex].getBufferSize(); - return LSize > RSize; - }); - - // Parallel optimizer + codegen - { - ThreadPool Pool(ThreadCount); - for (auto IndexCount : ModulesOrdering) { - auto &ModuleBuffer = Modules[IndexCount]; - Pool.async([&](int count) { - auto ModuleIdentifier = ModuleBuffer.getBufferIdentifier(); - auto &ExportList = ExportLists[ModuleIdentifier]; - - auto &DefinedFunctions = ModuleToDefinedGVSummaries[ModuleIdentifier]; - - // The module may be cached, this helps handling it. - ModuleCacheEntry CacheEntry(CacheOptions.Path, *Index, ModuleIdentifier, - ImportLists[ModuleIdentifier], ExportList, - ResolvedODR[ModuleIdentifier], - DefinedFunctions, GUIDPreservedSymbols); - - { - auto ErrOrBuffer = CacheEntry.tryLoadingBuffer(); - DEBUG(dbgs() << "Cache " << (ErrOrBuffer ? "hit" : "miss") << " '" - << CacheEntry.getEntryPath() << "' for buffer " << count - << " " << ModuleIdentifier << "\n"); - - if (ErrOrBuffer) { - // Cache Hit! - ProducedBinaries[count] = std::move(ErrOrBuffer.get()); - return; - } - } + // For each input, build the actual Resolution vector, and add the input to + // the CodeGen. + for (auto &Input : Inputs) { + std::vector Resolutions; + for (const lto::InputFile::Symbol &Sym : Input->symbols()) { + assert(!Sym.getName().empty()); + + lto::SymbolResolution Resolution; + + auto PrevailingInput = PrevailingSymbols.find(Sym.getName()); + if (PrevailingInput != PrevailingSymbols.end()) { + // If this symbol is in the map, we know for sure that the final + // definition + // is in the linkage unit. With better linker information, we could have + // the list of symbol defined in non-LTO files... + Resolution.FinalDefinitionInLinkageUnit = true; + + // If this occurence of the symbol is the prevailing one, mark it. + if (PrevailingInput->second.first == Input.get()) + Resolution.Prevailing = true; + } + + // If the linker asked the symbol to be preserved, it needs to be marked + // as visible outside the LTO unit / to regular objects. + if (PreservedSymbols.empty() || PreservedSymbols.count(Sym.getName())) + Resolution.VisibleToRegularObj = true; + + Resolutions.push_back(Resolution); + } - LLVMContext Context; - Context.setDiscardValueNames(LTODiscardValueNames); - Context.enableDebugTypeODRUniquing(); + Error Err = Codegen.add(std::move(Input), Resolutions); + if (Err) + report_fatal_error("FATAL"); + } +} - // Parse module now - auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false); +// Main entry point for the ThinLTO processing +void ThinLTOCodeGenerator::run() { + auto Conf = getLTOConfig(); + lto::ThinBackend Backend = lto::createInProcessThinBackend(ThreadCount); + lto::LTO Codegen(std::move(Conf), Backend); + + // Add inputs to the CodeGenerator and get it ready for processing. + populateCodeGenerator(Codegen); + + // We have no guarantee that all Tasks will feed an output buffer. So we use + // an intermediate vector to store each possible output. + std::vector> OutputBuffers; + OutputBuffers.resize(Codegen.getMaxTasks()); + // Callback for the LTO API. + auto AddOutput = + [&](unsigned Task) -> std::unique_ptr { + if (Task > OutputBuffers.size()) + report_fatal_error("Got an output for out-of-bound task"); + if (CacheOptions.Path.empty()) + return llvm::make_unique(OutputBuffers[Task]); + return llvm::make_unique( + CacheOptions.Path, [&OutputBuffers, Task](std::string EntryPath) { + // Load the entry from the cache now. + auto BufferOrErr = MemoryBuffer::getFile(EntryPath); + if (auto EC = BufferOrErr.getError()) + report_fatal_error(Twine("Can't reload cached file '") + EntryPath + + "': " + EC.message() + "\n"); + OutputBuffers[Task] = std::move(*BufferOrErr); + }); + }; - // Save temps: original file. - saveTempBitcode(*TheModule, SaveTempsDir, count, ".0.original.bc"); + // Run the actual optimizations/codegen now. + auto Err = Codegen.run(AddOutput); + if (Err) + report_fatal_error("FATAL: Codegen.run error: " + toString(std::move(Err))); - auto &ImportList = ImportLists[ModuleIdentifier]; - // Run the main process now, and generates a binary - auto OutputBuffer = ProcessThinLTOModule( - *TheModule, *Index, ModuleMap, *TMBuilder.create(), ImportList, - ExportList, GUIDPreservedSymbols, - ModuleToDefinedGVSummaries[ModuleIdentifier], CacheOptions, - DisableCodeGen, SaveTempsDir, count); + // Gather all the outputs, and generates the ProducedBinaries outputs. + for (auto &Buffer : OutputBuffers) + if (Buffer) + ProducedBinaries.push_back(std::move(Buffer)); - OutputBuffer = CacheEntry.write(std::move(OutputBuffer)); - ProducedBinaries[count] = std::move(OutputBuffer); - }, IndexCount); - } - } + // This is pedantic for now, and could be lifted. + if (ProducedBinaries.size() != Modules.size()) + report_fatal_error(Twine("FATAL: inconsistent number of outputs: got ") + + Twine(ProducedBinaries.size()) + " outputs but had " + + Twine(Modules.size()) + " inputs"); + // Prune the cache directory CachePruning(CacheOptions.Path) .setPruningInterval(CacheOptions.PruningInterval) .setEntryExpiration(CacheOptions.Expiration) Index: test/ThinLTO/X86/Inputs/alias_import.ll =================================================================== --- test/ThinLTO/X86/Inputs/alias_import.ll +++ test/ThinLTO/X86/Inputs/alias_import.ll @@ -1,4 +1,5 @@ - +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" Index: test/ThinLTO/X86/Inputs/alias_resolution.ll =================================================================== --- test/ThinLTO/X86/Inputs/alias_resolution.ll +++ test/ThinLTO/X86/Inputs/alias_resolution.ll @@ -1,5 +1,5 @@ - - +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" @globalfuncAlias = alias void (...), bitcast (void ()* @globalfunc to void (...)*) @@ -22,7 +22,6 @@ ret void } -@linkonceODRfuncAlias = alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) @linkonceODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) @linkonceODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) @linkonceODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) @@ -32,7 +31,6 @@ ret void } -@weakODRfuncAlias = alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) @weakODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) @weakODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) @weakODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) @@ -42,7 +40,6 @@ ret void } -@linkoncefuncAlias = alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) @linkoncefuncWeakAlias = weak alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) @linkoncefuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) @linkoncefuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) @@ -52,7 +49,6 @@ ret void } -@weakfuncAlias = alias void (...), bitcast (void ()* @weakfunc to void (...)*) @weakfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakfunc to void (...)*) @weakfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakfunc to void (...)*) @weakfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakfunc to void (...)*) Index: test/ThinLTO/X86/Inputs/section.ll =================================================================== --- test/ThinLTO/X86/Inputs/section.ll +++ test/ThinLTO/X86/Inputs/section.ll @@ -1,3 +1,6 @@ +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + ; An internal global variable that can't be renamed because it has a section @var_with_section = internal global i32 0, section "some_section" Index: test/ThinLTO/X86/Inputs/select_right_alias_definition1.ll =================================================================== --- test/ThinLTO/X86/Inputs/select_right_alias_definition1.ll +++ test/ThinLTO/X86/Inputs/select_right_alias_definition1.ll @@ -1,6 +1,8 @@ +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" @foo = weak alias i32 (...), bitcast (i32 ()* @foo1 to i32 (...)*) define i32 @foo1() { ret i32 42 } \ No newline at end of file Index: test/ThinLTO/X86/Inputs/select_right_alias_definition2.ll =================================================================== --- test/ThinLTO/X86/Inputs/select_right_alias_definition2.ll +++ test/ThinLTO/X86/Inputs/select_right_alias_definition2.ll @@ -1,3 +1,5 @@ +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" @foo = alias i32 (...), bitcast (i32 ()* @foo2 to i32 (...)*) Index: test/ThinLTO/X86/alias_import.ll =================================================================== --- test/ThinLTO/X86/alias_import.ll +++ test/ThinLTO/X86/alias_import.ll @@ -1,9 +1,11 @@ ; RUN: opt -module-summary %s -o %t1.bc ; RUN: opt -module-summary %p/Inputs/alias_import.ll -o %t2.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc -; RUN: llvm-lto -thinlto-action=promote -thinlto-index %t.index.bc %t2.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=PROMOTE -; RUN: llvm-lto -thinlto-action=promote -thinlto-index %t.index.bc %t2.bc -o - | llvm-lto -thinlto-action=internalize -thinlto-index %t.index.bc -thinlto-module-id=%t2.bc - -o - | llvm-dis -o - | FileCheck %s --check-prefix=PROMOTE-INTERNALIZE -; RUN: llvm-lto -thinlto-action=import -thinlto-index %t.index.bc %t1.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT +; RUN: llvm-lto -thinlto-action=promote -exported-symbol=_main %t1.bc %t2.bc +; RUN: llvm-dis %t2.bc.thinlto.promote.bc -o - | FileCheck %s --check-prefix=PROMOTE +; RUN: llvm-lto -thinlto-action=internalize -exported-symbol=_main %t1.bc %t2.bc +; RUN: llvm-dis %t2.bc.thinlto.internalize.bc -o - | FileCheck %s --check-prefix=PROMOTE-INTERNALIZE +; RUN: llvm-lto -thinlto-action=import -exported-symbol=_main %t1.bc %t2.bc +; RUN: llvm-dis %t1.bc.thinlto.import.bc -o - | FileCheck %s --check-prefix=IMPORT ; ; Alias can't point to "available_externally", so we can only import an alias @@ -46,10 +48,10 @@ ; These will be imported, check the linkage/renaming after promotion ; PROMOTE-DAG: define void @globalfunc() ; PROMOTE-DAG: define hidden void @internalfunc.llvm.0() -; PROMOTE-DAG: define linkonce_odr void @linkonceODRfunc() -; PROMOTE-DAG: define weak_odr void @weakODRfunc() -; PROMOTE-DAG: define linkonce void @linkoncefunc() -; PROMOTE-DAG: define weak void @weakfunc() +; PROMOTE-DAG: define internal void @linkonceODRfunc() +; PROMOTE-DAG: define internal void @weakODRfunc() +; PROMOTE-DAG: define internal void @linkoncefunc() +; PROMOTE-DAG: define internal void @weakfunc() ; On the import side now, verify that aliases to a linkonce_odr are imported, but the weak/linkonce (we can't inline them) ; IMPORT-DAG: declare void @linkonceODRfuncWeakAlias @@ -87,39 +89,37 @@ ; IMPORT-DAG: declare void @weakfuncWeakODRAlias() ; IMPORT-DAG: declare void @weakfuncLinkonceODRAlias() -; Promotion + internalization should internalize all of these, except for aliases of -; linkonce_odr functions, because alias to linkonce_odr are the only aliases we will -; import (see selectCallee() in FunctionImport.cpp). -; PROMOTE-INTERNALIZE-DAG: @globalfuncAlias = internal alias void (...), bitcast (void ()* @globalfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @globalfuncWeakAlias = internal alias void (...), bitcast (void ()* @globalfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @globalfuncLinkonceAlias = internal alias void (...), bitcast (void ()* @globalfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @globalfuncWeakODRAlias = internal alias void (...), bitcast (void ()* @globalfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @globalfuncLinkonceODRAlias = internal alias void (...), bitcast (void ()* @globalfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @internalfuncAlias = internal alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @internalfuncWeakAlias = internal alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @internalfuncLinkonceAlias = internal alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @internalfuncWeakODRAlias = internal alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @internalfuncLinkonceODRAlias = internal alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; Promotion + internalization should not internalize the functions called from main. +; PROMOTE-INTERNALIZE-DAG: @globalfuncAlias = alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @globalfuncWeakAlias = weak alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @globalfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @globalfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @globalfuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @internalfuncAlias = alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @internalfuncWeakAlias = weak alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @internalfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @internalfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @internalfuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) ; PROMOTE-INTERNALIZE-DAG: @linkonceODRfuncAlias = alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @linkonceODRfuncWeakAlias = internal alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @linkonceODRfuncLinkonceAlias = internal alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @linkonceODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @linkonceODRfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) ; PROMOTE-INTERNALIZE-DAG: @linkonceODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) ; PROMOTE-INTERNALIZE-DAG: @linkonceODRfuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakODRfuncAlias = internal alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakODRfuncWeakAlias = internal alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakODRfuncLinkonceAlias = internal alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakODRfuncWeakODRAlias = internal alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakODRfuncLinkonceODRAlias = internal alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @linkoncefuncAlias = internal alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @linkoncefuncWeakAlias = internal alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @linkoncefuncLinkonceAlias = internal alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @linkoncefuncWeakODRAlias = internal alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @linkoncefuncLinkonceODRAlias = internal alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakfuncAlias = internal alias void (...), bitcast (void ()* @weakfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakfuncWeakAlias = internal alias void (...), bitcast (void ()* @weakfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakfuncLinkonceAlias = internal alias void (...), bitcast (void ()* @weakfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakfuncWeakODRAlias = internal alias void (...), bitcast (void ()* @weakfunc to void (...)*) -; PROMOTE-INTERNALIZE-DAG: @weakfuncLinkonceODRAlias = internal alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakODRfuncAlias = alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakODRfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakODRfuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @linkoncefuncAlias = alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @linkoncefuncWeakAlias = weak alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @linkoncefuncLinkonceAlias = weak alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @linkoncefuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @linkoncefuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakfuncAlias = alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-INTERNALIZE-DAG: @weakfuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @weakfunc to void (...)*) ; PROMOTE-INTERNALIZE-DAG: define internal void @globalfunc() ; PROMOTE-INTERNALIZE-DAG: define internal void @internalfunc.llvm.0() ; PROMOTE-INTERNALIZE-DAG: define internal void @linkonceODRfunc() @@ -127,6 +127,10 @@ ; PROMOTE-INTERNALIZE-DAG: define internal void @linkoncefunc() ; PROMOTE-INTERNALIZE-DAG: define internal void @weakfunc() +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + + define i32 @main() #0 { entry: call void @globalfuncAlias() Index: test/ThinLTO/X86/alias_resolution.ll =================================================================== --- test/ThinLTO/X86/alias_resolution.ll +++ test/ThinLTO/X86/alias_resolution.ll @@ -1,13 +1,11 @@ ; RUN: opt -module-summary %s -o %t1.bc ; RUN: opt -module-summary %p/Inputs/alias_resolution.ll -o %t2.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc -; RUN: llvm-lto -thinlto-action=promote -thinlto-index %t.index.bc %t2.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=PROMOTE_MOD2 --check-prefix=NOTPROMOTED -; RUN: llvm-lto -thinlto-action=promote -thinlto-index %t.index.bc %t1.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=PROMOTE_MOD1 --check-prefix=NOTPROMOTED +; RUN: llvm-lto -thinlto-action=promote %t1.bc %t2.bc +; RUN: llvm-dis %t1.bc.thinlto.promote.bc -o - | FileCheck %s --check-prefix=PROMOTE_MOD1 --check-prefix=NOTPROMOTED +; RUN: llvm-dis %t2.bc.thinlto.promote.bc -o - | FileCheck %s --check-prefix=PROMOTE_MOD2 --check-prefix=NOTPROMOTED ; There is no importing going on with this IR, but let's check the ODR resolution for compile time -; NOTPROMOTED: @linkonceODRfuncAlias = alias void (...), bitcast (void ()* @linkonceODRfunc{{.*}} to void (...)*) -; NOTPROMOTED: @linkonceODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @linkonceODRfunc{{.*}} to void (...)*) ; PROMOTE_MOD1: @linkonceODRfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @linkonceODRfunc{{.*}} to void (...)*) ; PROMOTE_MOD2: @linkonceODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkonceODRfunc{{.*}} to void (...)*) ; PROMOTE_MOD1: @linkonceODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc.mod1 to void (...)*) @@ -15,7 +13,6 @@ ; PROMOTE_MOD1: @linkonceODRfuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc.mod1 to void (...)*) ; PROMOTE_MOD2: @linkonceODRfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) -; NOTPROMOTED: @weakODRfuncAlias = alias void (...), bitcast (void ()* @weakODRfunc{{.*}} to void (...)*) ; NOTPROMOTED: @weakODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakODRfunc{{.*}} to void (...)*) ; PROMOTE_MOD1: @weakODRfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @weakODRfunc{{.*}} to void (...)*) ; PROMOTE_MOD2: @weakODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakODRfunc{{.*}} to void (...)*) @@ -24,7 +21,6 @@ ; PROMOTE_MOD1: @weakODRfuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @weakODRfunc.mod1 to void (...)*) ; PROMOTE_MOD2: @weakODRfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) -; NOTPROMOTED: @linkoncefuncAlias = alias void (...), bitcast (void ()* @linkoncefunc{{.*}} to void (...)*) ; NOTPROMOTED: @linkoncefuncWeakAlias = weak alias void (...), bitcast (void ()* @linkoncefunc{{.*}} to void (...)*) ; PROMOTE_MOD1: @linkoncefuncLinkonceAlias = weak alias void (...), bitcast (void ()* @linkoncefunc{{.*}} to void (...)*) ; PROMOTE_MOD2: @linkoncefuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkoncefunc{{.*}} to void (...)*) @@ -33,7 +29,6 @@ ; PROMOTE_MOD1: @linkoncefuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @linkoncefunc.mod1 to void (...)*) ; PROMOTE_MOD2: @linkoncefuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) -; NOTPROMOTED: @weakfuncAlias = alias void (...), bitcast (void ()* @weakfunc{{.*}} to void (...)*) ; NOTPROMOTED: @weakfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakfunc{{.*}} to void (...)*) ; PROMOTE_MOD1: @weakfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @weakfunc{{.*}} to void (...)*) ; PROMOTE_MOD2: @weakfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakfunc{{.*}} to void (...)*) @@ -44,7 +39,9 @@ ; PROMOTE_MOD2: @weakfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @weakfunc to void (...)*) -@linkonceODRfuncAlias = alias void (...), bitcast (void ()* @linkonceODRfunc.mod1 to void (...)*) +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + @linkonceODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @linkonceODRfunc.mod1 to void (...)*) @linkonceODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkonceODRfunc.mod1 to void (...)*) @linkonceODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc.mod1 to void (...)*) @@ -54,7 +51,6 @@ ret void } -@weakODRfuncAlias = alias void (...), bitcast (void ()* @weakODRfunc.mod1 to void (...)*) @weakODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakODRfunc.mod1 to void (...)*) @weakODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakODRfunc.mod1 to void (...)*) @weakODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakODRfunc.mod1 to void (...)*) @@ -64,7 +60,6 @@ ret void } -@linkoncefuncAlias = alias void (...), bitcast (void ()* @linkoncefunc.mod1 to void (...)*) @linkoncefuncWeakAlias = weak alias void (...), bitcast (void ()* @linkoncefunc.mod1 to void (...)*) @linkoncefuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkoncefunc.mod1 to void (...)*) @linkoncefuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkoncefunc.mod1 to void (...)*) @@ -74,7 +69,6 @@ ret void } -@weakfuncAlias = alias void (...), bitcast (void ()* @weakfunc.mod1 to void (...)*) @weakfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakfunc.mod1 to void (...)*) @weakfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakfunc.mod1 to void (...)*) @weakfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakfunc.mod1 to void (...)*) Index: test/ThinLTO/X86/autoupgrade.ll =================================================================== --- test/ThinLTO/X86/autoupgrade.ll +++ test/ThinLTO/X86/autoupgrade.ll @@ -1,9 +1,8 @@ ; Verify that auto-upgrading intrinsics works with Lazy loaded bitcode ; Do setup work for all below tests: generate bitcode and combined index ; RUN: opt -module-summary %s -o %t.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %p/Inputs/autoupgrade.bc - -; RUN: llvm-lto -thinlto-action=import %t.bc -thinlto-index=%t3.bc -o - | llvm-bcanalyzer -dump | FileCheck %s +; RUN: llvm-lto -thinlto-action=import %t.bc %p/Inputs/autoupgrade.bc +; RUN: llvm-bcanalyzer -dump %t.bc.thinlto.import.bc | FileCheck %s ; We can't use llvm-dis here, because it would do the autoupgrade itself. Index: test/ThinLTO/X86/deadstrip.ll =================================================================== --- test/ThinLTO/X86/deadstrip.ll +++ test/ThinLTO/X86/deadstrip.ll @@ -2,7 +2,8 @@ ; RUN: opt -module-summary %p/Inputs/deadstrip.ll -o %t2.bc ; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc -; RUN: llvm-lto -exported-symbol=_main -thinlto-action=promote %t1.bc -thinlto-index=%t.index.bc -o - | llvm-lto -exported-symbol=_main -thinlto-action=internalize -thinlto-index %t.index.bc -thinlto-module-id=%t1.bc - -o - | llvm-dis -o - | FileCheck %s +; RUN: llvm-lto -exported-symbol=_main -thinlto-action=internalize -thinlto-index %t.index.bc %t1.bc +; RUN: llvm-dis %t1.bc.thinlto.internalize.bc -o - | FileCheck %s ; RUN: llvm-lto -exported-symbol=_main -thinlto-action=run %t1.bc %t2.bc ; RUN: llvm-nm %t1.bc.thinlto.o | FileCheck %s --check-prefix=CHECK-NM Index: test/ThinLTO/X86/drop-debug-info.ll =================================================================== --- test/ThinLTO/X86/drop-debug-info.ll +++ test/ThinLTO/X86/drop-debug-info.ll @@ -1,9 +1,9 @@ ; RUN: opt -module-summary %s -o %t.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t.bc %p/Inputs/drop-debug-info.bc ; The imported module has out-of-date debug information, let's make sure we can ; drop them without crashing when materializing later. -; RUN: llvm-lto -thinlto-action=import %t.bc -thinlto-index=%t.index.bc -o - | llvm-dis -o - | FileCheck %s +; RUN: llvm-lto -thinlto-action=import %t.bc +; RUNL llvm-dis %t.bc.thinlto.import.bc -o - | FileCheck %s ; CHECK: define available_externally void @globalfunc ; CHECK-NOT: llvm.dbg.value Index: test/ThinLTO/X86/funcimport.ll =================================================================== --- test/ThinLTO/X86/funcimport.ll +++ test/ThinLTO/X86/funcimport.ll @@ -1,7 +1,6 @@ ; Do setup work for all below tests: generate bitcode and combined index ; RUN: opt -module-summary %s -o %t.bc ; RUN: opt -module-summary %p/Inputs/funcimport.ll -o %t2.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %t2.bc ; Ensure statics are promoted/renamed correctly from this file (all but ; constant variable need promotion). @@ -17,7 +16,8 @@ ; Also ensures that alias to a linkonce function is turned into a declaration ; and that the associated linkonce function is not in the output, as it is ; lazily linked and never referenced/materialized. -; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORTGLOB1 +; RUN: llvm-lto -thinlto-action=import %t.bc %t2.bc +; RUN: llvm-dis %t2.bc.thinlto.import.bc -o - | FileCheck %s --check-prefix=IMPORTGLOB1 ; IMPORTGLOB1-DAG: define available_externally void @globalfunc1 ; IMPORTGLOB1-DAG: declare void @weakalias ; IMPORTGLOB1-DAG: declare void @analias Index: test/ThinLTO/X86/internalize.ll =================================================================== --- test/ThinLTO/X86/internalize.ll +++ test/ThinLTO/X86/internalize.ll @@ -1,7 +1,7 @@ -;; RUN: opt -module-summary %s -o %t1.bc +; RUN: opt -module-summary %s -o %t1.bc ; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc ; RUN: llvm-lto -thinlto-action=internalize -thinlto-index %t.index.bc %t1.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=REGULAR -; RUN: llvm-lto -thinlto-action=internalize -thinlto-index %t.index.bc %t1.bc -o - --exported-symbol=foo | llvm-dis -o - | FileCheck %s --check-prefix=INTERNALIZE +; RUN: llvm-lto -thinlto-action=internalize -thinlto-index %t.index.bc %t1.bc -o - --exported-symbol=_foo | llvm-dis -o - | FileCheck %s --check-prefix=INTERNALIZE ; RUN: llvm-lto2 %t1.bc -o %t.o -save-temps \ ; RUN: -r=%t1.bc,_foo,pxl \ @@ -12,7 +12,7 @@ ; REGULAR: define void @foo ; REGULAR: define void @bar -; REGULAR: define linkonce void @linkonce_func() +; REGULAR: define weak void @linkonce_func() ; INTERNALIZE: define void @foo ; INTERNALIZE: define internal void @bar ; INTERNALIZE: define internal void @linkonce_func() Index: test/ThinLTO/X86/linkonce_resolution_comdat.ll =================================================================== --- test/ThinLTO/X86/linkonce_resolution_comdat.ll +++ test/ThinLTO/X86/linkonce_resolution_comdat.ll @@ -5,8 +5,8 @@ ; RUN: opt -module-summary %p/Inputs/linkonce_resolution_comdat.ll -o %t2.bc ; RUN: llvm-lto -thinlto-action=run %t1.bc %t2.bc -exported-symbol=f -exported-symbol=g -thinlto-save-temps=%t3. -; RUN: llvm-dis %t3.0.3.imported.bc -o - | FileCheck %s --check-prefix=IMPORT1 -; RUN: llvm-dis %t3.1.3.imported.bc -o - | FileCheck %s --check-prefix=IMPORT2 +; RUN: llvm-dis %t3.0.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT1 +; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT2 ; Copy from first module is prevailing and converted to weak_odr, copy ; from second module is preempted and converted to available_externally and ; removed from comdat. Index: test/ThinLTO/X86/llvm.used.ll =================================================================== --- test/ThinLTO/X86/llvm.used.ll +++ test/ThinLTO/X86/llvm.used.ll @@ -1,10 +1,9 @@ ; Do setup work for all below tests: generate bitcode and combined index ; RUN: opt -module-summary %s -o %t.bc ; RUN: opt -module-summary %p/Inputs/llvm.used.ll -o %t2.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %t2.bc - -; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s +; RUN: llvm-lto -thinlto-action=import %t.bc %t2.bc +; RUN: llvm-dis %t2.bc.thinlto.import.bc -o - | FileCheck %s ; CHECK: define available_externally void @globalfunc Index: test/ThinLTO/X86/referenced_by_constant.ll =================================================================== --- test/ThinLTO/X86/referenced_by_constant.ll +++ test/ThinLTO/X86/referenced_by_constant.ll @@ -1,10 +1,10 @@ ; Do setup work for all below tests: generate bitcode and combined index ; RUN: opt -module-summary %s -o %t.bc ; RUN: opt -module-summary %p/Inputs/referenced_by_constant.ll -o %t2.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %t2.bc ; Check the import side: we import bar() and @someglobal, but not @referencedbyglobal() -; RUN: llvm-lto -thinlto-action=import %t.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT +; RUN: llvm-lto -thinlto-action=import %t.bc %t2.bc +; RUN: llvm-dis %t.bc.thinlto.import.bc -o - | FileCheck %s --check-prefix=IMPORT ; IMPORT: @someglobal.llvm.0 = ; IMPORT: define available_externally void @bar() ; IMPORT: declare void @referencedbyglobal() Index: test/ThinLTO/X86/section.ll =================================================================== --- test/ThinLTO/X86/section.ll +++ test/ThinLTO/X86/section.ll @@ -1,18 +1,21 @@ ; Do setup work for all below tests: generate bitcode and combined index ; RUN: opt -module-summary %s -o %t.bc ; RUN: opt -module-summary %p/Inputs/section.ll -o %t2.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %t2.bc ; Check that we don't promote 'var_with_section' -; RUN: llvm-lto -thinlto-action=promote %t2.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=PROMOTE +; RUN: llvm-lto -thinlto-action=promote %t.bc %t2.bc +; RUN: llvm-dis %t2.bc.thinlto.promote.bc -o - | FileCheck %s --check-prefix=PROMOTE ; PROMOTE: @var_with_section = internal global i32 0, section "some_section" -; RUN: llvm-lto -thinlto-action=import %t.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT +; RUN: llvm-lto -thinlto-action=import %t.bc %t2.bc +; RUN: llvm-dis %t.bc.thinlto.import.bc -o - | FileCheck %s --check-prefix=IMPORT ; Check that section prevent import of @reference_gv_with_section. ; IMPORT: declare void @reference_gv_with_section() ; Canary to check that importing is correctly set up. ; IMPORT: define available_externally void @foo() +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" define i32 @main() { call void @reference_gv_with_section() Index: test/ThinLTO/X86/select_right_alias_definition.ll =================================================================== --- test/ThinLTO/X86/select_right_alias_definition.ll +++ test/ThinLTO/X86/select_right_alias_definition.ll @@ -6,12 +6,12 @@ ; order the files are linked in. ; Try with one order -; RUN: llvm-lto -thinlto-action=thinlink -o %t.index1.bc %t_main.bc %t1.bc %t2.bc -; RUN: llvm-lto -thinlto-action=import -thinlto-index %t.index1.bc %t_main.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT +; RUN: llvm-lto -thinlto-action=import %t_main.bc %t1.bc %t2.bc +; RUN: llvm-dis %t_main.bc.thinlto.import.bc -o - | FileCheck %s --check-prefix=IMPORT ; Try with the other order (reversing %t1.bc and %t2.bc) -; RUN: llvm-lto -thinlto-action=thinlink -o %t.index2.bc %t_main.bc %t2.bc %t1.bc -; RUN: llvm-lto -thinlto-action=import -thinlto-index %t.index2.bc %t_main.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT +; RUN: llvm-lto -thinlto-action=import %t_main.bc %t2.bc %t1.bc +; RUN: llvm-dis %t_main.bc.thinlto.import.bc -o - | FileCheck %s --check-prefix=IMPORT ; IMPORT: @foo = alias i32 (...), bitcast (i32 ()* @foo2 to i32 (...)*) ; IMPORT: define linkonce_odr i32 @foo2() { @@ -19,9 +19,12 @@ ; IMPORT-NEXT: ret i32 %ret ; IMPORT-NEXT: } +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + declare i32 @foo() define i32 @main() { %ret = call i32 @foo() ret i32 %ret } \ No newline at end of file Index: test/ThinLTO/X86/weak_resolution.ll =================================================================== --- test/ThinLTO/X86/weak_resolution.ll +++ test/ThinLTO/X86/weak_resolution.ll @@ -6,11 +6,15 @@ ; Verify that prevailing weak for linker symbol is selected across modules, ; non-prevailing ODR are not kept when possible, but non-ODR non-prevailing ; are not affected. -; RUN: llvm-lto -thinlto-action=promote %t.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=MOD1 -; RUN: llvm-lto -thinlto-action=promote %t.bc -thinlto-index=%t3.bc -exported-symbol=linkoncefunc -o - | llvm-lto -thinlto-action=internalize -thinlto-module-id=%t.bc - -thinlto-index=%t3.bc -exported-symbol=linkoncefunc -o - | llvm-dis -o - | FileCheck %s --check-prefix=MOD1-INT -; RUN: llvm-lto -thinlto-action=promote %t2.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=MOD2 +; RUN: llvm-lto -thinlto-action=promote %t.bc -thinlto-index=%t3.bc -o %t.promote.bc +; RUN: llvm-dis %t.promote.bc -o - | FileCheck %s --check-prefix=MOD1 +; RUN: llvm-lto -thinlto-action=internalize %t.bc %t2.bc -exported-symbol=_main +; RUN: llvm-dis %t.bc.thinlto.internalize.bc -o - | FileCheck %s --check-prefix=MOD1-INT +; RUN: llvm-lto -thinlto-action=promote %t.bc %t2.bc +; RUN: llvm-dis %t2.bc.thinlto.promote.bc -o - | FileCheck %s --check-prefix=MOD2 ; When exported, we always preserve a linkonce -; RUN: llvm-lto -thinlto-action=promote %t.bc -thinlto-index=%t3.bc -o - --exported-symbol=linkonceodrfuncInSingleModule | llvm-dis -o - | FileCheck %s --check-prefix=EXPORTED +; RUN: llvm-lto -thinlto-action=internalize %t.bc %t2.bc -exported-symbol=_linkoncefunc --exported-symbol=_linkonceodrfuncInSingleModule +; RUN: llvm-dis %t.bc.thinlto.internalize.bc -o - | FileCheck %s --check-prefix=EXPORTED target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.11.0" Index: test/ThinLTO/X86/weak_resolution_single.ll =================================================================== --- test/ThinLTO/X86/weak_resolution_single.ll +++ test/ThinLTO/X86/weak_resolution_single.ll @@ -1,7 +1,9 @@ ; RUN: opt -module-summary %s -o %t.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t2.bc %t.bc +; RUN: llvm-lto -thinlto-action=internalize %t.bc -thinlto-index=%t2.bc -exported-symbol=_foo -o %t.internalize.bc +; RUN: llvm-dis %t.internalize.bc -o - | FileCheck %s -; RUN: llvm-lto -thinlto-action=promote %t.bc -thinlto-index=%t2.bc -exported-symbol=foo -o - | llvm-lto -thinlto-action=internalize -thinlto-module-id=%t.bc - -thinlto-index=%t2.bc -exported-symbol=foo -o - | llvm-dis -o - | FileCheck %s +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" ; CHECK: define weak_odr void @foo() define linkonce_odr void @foo() { Index: tools/llvm-lto/llvm-lto.cpp =================================================================== --- tools/llvm-lto/llvm-lto.cpp +++ tools/llvm-lto/llvm-lto.cpp @@ -386,7 +386,7 @@ return M; } -static void writeModuleToFile(Module &TheModule, StringRef Filename) { +static void writeModuleToFile(const Module &TheModule, StringRef Filename) { std::error_code EC; raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::F_None); error(EC, "error opening the file '" + Filename + "'"); @@ -397,6 +397,7 @@ class ThinLTOProcessing { public: ThinLTOCodeGenerator ThinGenerator; + std::vector> InputBuffers; ThinLTOProcessing(const TargetOptions &Options) { ThinGenerator.setCodePICModel(getRelocModel()); @@ -432,6 +433,17 @@ } private: + void loadInputs() { + for (unsigned i = 0; i < InputFilenames.size(); ++i) { + auto &Filename = InputFilenames[i]; + StringRef CurrentActivity = "loading file '" + Filename + "'"; + auto InputOrErr = MemoryBuffer::getFile(Filename); + error(InputOrErr, "error " + CurrentActivity); + InputBuffers.push_back(std::move(*InputOrErr)); + ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer()); + } + } + /// Load the input files, create the combined index, and write it out. void thinLink() { // Perform "ThinLink": just produce the index @@ -526,19 +538,16 @@ "the output files will be suffixed from the input " "ones."); - auto Index = loadCombinedIndex(); - for (auto &Filename : InputFilenames) { - LLVMContext Ctx; - auto TheModule = loadModule(Filename, Ctx); - - ThinGenerator.promote(*TheModule, *Index); + loadInputs(); + ThinGenerator.promote([&](unsigned Id, const Module &TheModule) { std::string OutputName = OutputFilename; if (OutputName.empty()) { - OutputName = Filename + ".thinlto.promoted.bc"; + OutputName = TheModule.getModuleIdentifier(); + OutputName += ".thinlto.promote.bc"; } - writeModuleToFile(*TheModule, OutputName); - } + writeModuleToFile(TheModule, OutputName); + }); } /// Load the combined index from disk, then load every file referenced by @@ -552,24 +561,16 @@ "the output files will be suffixed from the input " "ones."); - auto Index = loadCombinedIndex(); - auto InputBuffers = loadAllFilesForIndex(*Index); - for (auto &MemBuffer : InputBuffers) - ThinGenerator.addModule(MemBuffer->getBufferIdentifier(), - MemBuffer->getBuffer()); - - for (auto &Filename : InputFilenames) { - LLVMContext Ctx; - auto TheModule = loadModule(Filename, Ctx); - - ThinGenerator.crossModuleImport(*TheModule, *Index); + loadInputs(); + ThinGenerator.crossModuleImport([&](unsigned Id, const Module &TheModule) { std::string OutputName = OutputFilename; if (OutputName.empty()) { - OutputName = Filename + ".thinlto.imported.bc"; + OutputName = TheModule.getModuleIdentifier(); + OutputName += ".thinlto.import.bc"; } - writeModuleToFile(*TheModule, OutputName); - } + writeModuleToFile(TheModule, OutputName); + }); } void internalize() { @@ -583,24 +584,16 @@ errs() << "Warning: -internalize will not perform without " "-exported-symbol\n"; - auto Index = loadCombinedIndex(); - auto InputBuffers = loadAllFilesForIndex(*Index); - for (auto &MemBuffer : InputBuffers) - ThinGenerator.addModule(MemBuffer->getBufferIdentifier(), - MemBuffer->getBuffer()); - - for (auto &Filename : InputFilenames) { - LLVMContext Ctx; - auto TheModule = loadModule(Filename, Ctx); - - ThinGenerator.internalize(*TheModule, *Index); + loadInputs(); + ThinGenerator.internalize([&](unsigned Id, const Module &TheModule) { std::string OutputName = OutputFilename; if (OutputName.empty()) { - OutputName = Filename + ".thinlto.internalized.bc"; + OutputName = TheModule.getModuleIdentifier(); + OutputName += ".thinlto.internalize.bc"; } - writeModuleToFile(*TheModule, OutputName); - } + writeModuleToFile(TheModule, OutputName); + }); } void optimize() {