Index: include/llvm/Linker/Linker.h =================================================================== --- include/llvm/Linker/Linker.h +++ include/llvm/Linker/Linker.h @@ -40,15 +40,14 @@ /// Passing OverrideSymbols as true will have symbols from Src /// shadow those in the Dest. /// For ThinLTO function importing/exporting the \p FunctionInfoIndex - /// is passed. If \p FunctionsToImport is provided, only the functions that + /// is passed. If \p GlobalsToImport is provided, only the globals that /// are part of the set will be imported from the source module. /// The \p ValIDToTempMDMap is populated by the linker when function /// importing is performed. /// /// Returns true on error. bool linkInModule(std::unique_ptr Src, unsigned Flags = Flags::None, - const FunctionInfoIndex *Index = nullptr, - DenseSet *FunctionsToImport = nullptr, + DenseSet *GlobalsToImport = nullptr, DenseMap *ValIDToTempMDMap = nullptr); static bool linkModules(Module &Dest, std::unique_ptr Src, Index: include/llvm/Transforms/Utils/FunctionImportUtils.h =================================================================== --- include/llvm/Transforms/Utils/FunctionImportUtils.h +++ include/llvm/Transforms/Utils/FunctionImportUtils.h @@ -30,9 +30,9 @@ /// Function index passed in for function importing/exporting handling. const FunctionInfoIndex &ImportIndex; - /// Functions to import from this module, all other functions will be + /// Globals to import from this module, all other functions will be /// imported as declarations instead of definitions. - DenseSet *FunctionsToImport; + DenseSet *GlobalsToImport; /// Set to true if the given FunctionInfoIndex contains any functions /// from this source module, in which case we must conservatively assume @@ -50,7 +50,7 @@ /// Helper methods to check if we are importing from or potentially /// exporting from the current source module. - bool isPerformingImport() const { return FunctionsToImport != nullptr; } + bool isPerformingImport() const { return GlobalsToImport != nullptr; } bool isModuleExporting() const { return HasExportedFunctions; } /// If we are importing from the source module, checks if we should @@ -77,13 +77,13 @@ public: FunctionImportGlobalProcessing( Module &M, const FunctionInfoIndex &Index, - DenseSet *FunctionsToImport = nullptr) - : M(M), ImportIndex(Index), FunctionsToImport(FunctionsToImport) { + DenseSet *GlobalsToImport = nullptr) + : M(M), ImportIndex(Index), GlobalsToImport(GlobalsToImport) { // If we have a FunctionInfoIndex but no function to import, // then this is the primary module being compiled in a ThinLTO // backend compilation, and we need to see if it has functions that // may be exported to another backend compilation. - if (!FunctionsToImport) + if (!GlobalsToImport) HasExportedFunctions = ImportIndex.hasExportedFunctions(M); } @@ -91,7 +91,7 @@ static bool doImportAsDefinition(const GlobalValue *SGV, - DenseSet *FunctionsToImport); + DenseSet *GlobalsToImport); /// Access the promoted globals that are now exported and need to be linked. SetVector &getNewExportedValues() { return NewExportedValues; } Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -35,19 +35,9 @@ /// For symbol clashes, prefer those from Src. unsigned Flags; - /// Function index passed into ModuleLinker for using in function - /// importing/exporting handling. - const FunctionInfoIndex *ImportIndex; - /// Functions to import from source module, all other functions are /// imported as declarations instead of definitions. - DenseSet *FunctionsToImport; - - /// Set to true if the given FunctionInfoIndex contains any functions - /// from this source module, in which case we must conservatively assume - /// that any of its functions may be imported into another module - /// as part of a different backend compilation process. - bool HasExportedFunctions = false; + DenseSet *GlobalsToImport; /// Association between metadata value id and temporary metadata that /// remains unmapped after function importing. Saved during function @@ -116,7 +106,7 @@ /// Helper method to check if we are importing from the current source /// module. - bool isPerformingImport() const { return FunctionsToImport != nullptr; } + bool isPerformingImport() const { return GlobalsToImport != nullptr; } /// If we are importing from the source module, checks if we should /// import SGV as a definition, otherwise import as a declaration. @@ -124,21 +114,10 @@ public: ModuleLinker(IRMover &Mover, std::unique_ptr SrcM, unsigned Flags, - const FunctionInfoIndex *Index = nullptr, - DenseSet *FunctionsToImport = nullptr, + DenseSet *GlobalsToImport = nullptr, DenseMap *ValIDToTempMDMap = nullptr) - : Mover(Mover), SrcM(std::move(SrcM)), Flags(Flags), ImportIndex(Index), - FunctionsToImport(FunctionsToImport), - ValIDToTempMDMap(ValIDToTempMDMap) { - assert((ImportIndex || !FunctionsToImport) && - "Expect a FunctionInfoIndex when importing"); - // If we have a FunctionInfoIndex but no function to import, - // then this is the primary module being compiled in a ThinLTO - // backend compilation, and we need to see if it has functions that - // may be exported to another backend compilation. - if (ImportIndex && !FunctionsToImport) - HasExportedFunctions = ImportIndex->hasExportedFunctions(*this->SrcM); - } + : Mover(Mover), SrcM(std::move(SrcM)), Flags(Flags), + GlobalsToImport(GlobalsToImport), ValIDToTempMDMap(ValIDToTempMDMap) {} bool run(); }; @@ -147,8 +126,8 @@ bool ModuleLinker::doImportAsDefinition(const GlobalValue *SGV) { if (!isPerformingImport()) return false; - return FunctionImportGlobalProcessing::doImportAsDefinition( - SGV, FunctionsToImport); + return FunctionImportGlobalProcessing::doImportAsDefinition(SGV, + GlobalsToImport); } static GlobalValue::VisibilityTypes @@ -297,7 +276,7 @@ if (isa(&Src)) { // For functions, LinkFromSrc iff this is a function requested // for importing. For variables, decide below normally. - LinkFromSrc = FunctionsToImport->count(&Src); + LinkFromSrc = GlobalsToImport->count(&Src); return false; } @@ -426,7 +405,8 @@ if (isPerformingImport() && !doImportAsDefinition(&GV)) return false; - if (!DGV && !shouldOverrideFromSrc() && + if (!(isPerformingImport() && GlobalsToImport->count(&GV)) && !DGV && + !shouldOverrideFromSrc() && (GV.hasLocalLinkage() || GV.hasLinkOnceLinkage() || GV.hasAvailableExternallyLinkage())) return false; @@ -508,15 +488,6 @@ if (linkIfNeeded(GA)) return true; - if (ImportIndex) { - FunctionImportGlobalProcessing ThinLTOProcessing(*SrcM, *ImportIndex, - FunctionsToImport); - if (ThinLTOProcessing.run()) - return true; - for (auto *GV : ThinLTOProcessing.getNewExportedValues()) - ValuesToLink.insert(GV); - } - for (unsigned I = 0; I < ValuesToLink.size(); ++I) { GlobalValue *GV = ValuesToLink[I]; const Comdat *SC = GV->getComdat(); @@ -549,10 +520,9 @@ Linker::Linker(Module &M) : Mover(M) {} bool Linker::linkInModule(std::unique_ptr Src, unsigned Flags, - const FunctionInfoIndex *Index, - DenseSet *FunctionsToImport, + DenseSet *GlobalsToImport, DenseMap *ValIDToTempMDMap) { - ModuleLinker ModLinker(Mover, std::move(Src), Flags, Index, FunctionsToImport, + ModuleLinker ModLinker(Mover, std::move(Src), Flags, GlobalsToImport, ValIDToTempMDMap); return ModLinker.run(); } Index: lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- lib/Transforms/IPO/FunctionImport.cpp +++ lib/Transforms/IPO/FunctionImport.cpp @@ -262,14 +262,6 @@ "', error in the summary?\n"); } - Function *F = dyn_cast(SGV); - if (!F && isa(SGV)) { - auto *SGA = dyn_cast(SGV); - F = dyn_cast(SGA->getBaseObject()); - CalledFunctionName = F->getName(); - } - assert(F && "Imported Function is ... not a Function"); - // We cannot import weak_any functions/aliases without possibly affecting // the order they are seen and selected by the linker, changing program // semantics. @@ -282,8 +274,16 @@ continue; } - // Add the function to the import list auto &Entry = ModuleToFunctionsToImportMap[SrcModule.getModuleIdentifier()]; + + Function *F = dyn_cast(SGV); + if (!F && isa(SGV)) { + auto *SGA = dyn_cast(SGV); + F = dyn_cast(SGA->getBaseObject()); + } + assert(F && "Imported Function is ... not a Function"); + + // Add the function to the import list Entry.insert(F); // Process the newly imported functions and add callees to the worklist. @@ -349,10 +349,17 @@ UpgradeDebugInfo(*SrcModule); // Link in the specified functions. + FunctionImportGlobalProcessing ThinLTOProcessing(*SrcModule, Index, + &FunctionsToImport); + if (ThinLTOProcessing.run()) + return true; + for (auto *GV : ThinLTOProcessing.getNewExportedValues()) + FunctionsToImport.insert(GV); + if (TheLinker.linkInModule(std::move(SrcModule), Linker::Flags::None, - &Index, &FunctionsToImport)) + &FunctionsToImport)) report_fatal_error("Function Import: link error"); - + ImportedCount += FunctionsToImport.size(); } Index: lib/Transforms/Utils/FunctionImportUtils.cpp =================================================================== --- lib/Transforms/Utils/FunctionImportUtils.cpp +++ lib/Transforms/Utils/FunctionImportUtils.cpp @@ -18,30 +18,20 @@ /// Checks if we should import SGV as a definition, otherwise import as a /// declaration. bool FunctionImportGlobalProcessing::doImportAsDefinition( - const GlobalValue *SGV, DenseSet *FunctionsToImport) { - auto *GA = dyn_cast(SGV); - if (GA) { + const GlobalValue *SGV, DenseSet *GlobalsToImport) { + + // For alias, we tie the definition to the base object. Extract it and recurse + if (auto *GA = dyn_cast(SGV)) { if (GA->hasWeakAnyLinkage()) return false; const GlobalObject *GO = GA->getBaseObject(); if (!GO->hasLinkOnceODRLinkage()) return false; return FunctionImportGlobalProcessing::doImportAsDefinition( - GO, FunctionsToImport); + GO, GlobalsToImport); } - // Always import GlobalVariable definitions, except for the special - // case of WeakAny which are imported as ExternalWeak declarations - // (see comments in FunctionImportGlobalProcessing::getLinkage). The linkage - // changes described in FunctionImportGlobalProcessing::getLinkage ensure the - // correct behavior (e.g. global variables with external linkage are - // transformed to available_externally definitions, which are ultimately - // turned into declarations after the EliminateAvailableExternally pass). - if (isa(SGV) && !SGV->isDeclaration() && - !SGV->hasWeakAnyLinkage()) - return true; - // Only import the function requested for importing. - auto *SF = dyn_cast(SGV); - if (SF && FunctionsToImport->count(SF)) + // Only import the globals requested for importing. + if (GlobalsToImport->count(SGV)) return true; // Otherwise no. return false; @@ -51,8 +41,8 @@ const GlobalValue *SGV) { if (!isPerformingImport()) return false; - return FunctionImportGlobalProcessing::doImportAsDefinition( - SGV, FunctionsToImport); + return FunctionImportGlobalProcessing::doImportAsDefinition(SGV, + GlobalsToImport); } bool FunctionImportGlobalProcessing::doPromoteLocalToGlobal( Index: test/Linker/funcimport.ll =================================================================== --- test/Linker/funcimport.ll +++ test/Linker/funcimport.ll @@ -67,7 +67,7 @@ ; Ensure that imported static variable and function references are correctly ; promoted and renamed (including static constant variable). ; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=referencestatics:%t.bc -S | FileCheck %s --check-prefix=IMPORTSTATIC -; IMPORTSTATIC-DAG: @staticvar.llvm.1 = available_externally hidden global +; IMPORTSTATIC-DAG: @staticvar.llvm.1 = external hidden global ; IMPORTSTATIC-DAG: @staticconstvar.llvm.1 = internal unnamed_addr constant ; IMPORTSTATIC-DAG: define available_externally i32 @referencestatics ; IMPORTSTATIC-DAG: %call = call i32 @staticfunc.llvm.1 @@ -78,18 +78,18 @@ ; are handled correctly (including referenced variable imported as ; available_externally definition) ; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=referenceglobals:%t.bc -S | FileCheck %s --check-prefix=IMPORTGLOBALS -; IMPORTGLOBALS-DAG: @globalvar = available_externally global +; IMPORTGLOBALS-DAG: @globalvar = external global ; IMPORTGLOBALS-DAG: declare void @globalfunc1() ; IMPORTGLOBALS-DAG: define available_externally i32 @referenceglobals ; Ensure that common variable correctly imported as common defition. ; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=referencecommon:%t.bc -S | FileCheck %s --check-prefix=IMPORTCOMMON -; IMPORTCOMMON-DAG: @commonvar = common global +; IMPORTCOMMON-DAG: @commonvar = external global ; IMPORTCOMMON-DAG: define available_externally i32 @referencecommon ; Ensure that imported static function pointer correctly promoted and renamed. ; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=callfuncptr:%t.bc -S | FileCheck %s --check-prefix=IMPORTFUNCPTR -; IMPORTFUNCPTR-DAG: @P.llvm.1 = available_externally hidden global void ()* null +; IMPORTFUNCPTR-DAG: @P.llvm.1 = external hidden global void ()* ; IMPORTFUNCPTR-DAG: define available_externally void @callfuncptr ; IMPORTFUNCPTR-DAG: %0 = load void ()*, void ()** @P.llvm.1 Index: test/Transforms/FunctionImport/Inputs/funcimport.ll =================================================================== --- test/Transforms/FunctionImport/Inputs/funcimport.ll +++ test/Transforms/FunctionImport/Inputs/funcimport.ll @@ -1,5 +1,6 @@ @globalvar = global i32 1, align 4 @staticvar = internal global i32 1, align 4 +@staticvar2 = internal global i32 1, align 4 @staticconstvar = internal unnamed_addr constant [2 x i32] [i32 10, i32 20], align 4 @commonvar = common global i32 0, align 4 @P = internal global void ()* null, align 8 @@ -19,6 +20,13 @@ ret void } +define void @globalfunc3() #0 { +entry: + %0 = load i32, i32* @staticvar2, align 4 + ret void +} + + define linkonce_odr void @linkoncefunc() #0 { entry: ret void Index: test/Transforms/FunctionImport/funcimport.ll =================================================================== --- test/Transforms/FunctionImport/funcimport.ll +++ test/Transforms/FunctionImport/funcimport.ll @@ -65,7 +65,7 @@ ; Ensure that all uses of local variable @P which has used in setfuncptr ; and callfuncptr are to the same promoted/renamed global. -; CHECK-DAG: @P.llvm.2 = available_externally hidden global void ()* null +; CHECK-DAG: @P.llvm.2 = external hidden global void ()* ; CHECK-DAG: %0 = load void ()*, void ()** @P.llvm.2, ; CHECK-DAG: store void ()* @staticfunc2.llvm.2, void ()** @P.llvm.2, Index: tools/llvm-link/llvm-link.cpp =================================================================== --- tools/llvm-link/llvm-link.cpp +++ tools/llvm-link/llvm-link.cpp @@ -33,6 +33,8 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Transforms/Utils/FunctionImportUtils.h" + #include using namespace llvm; @@ -192,6 +194,10 @@ if (Verbose) errs() << "Importing " << FunctionName << " from " << FileName << "\n"; + // Link in the specified function. + DenseSet GlobalsToImport; + GlobalsToImport.insert(F); + std::unique_ptr Index; if (!FunctionIndex.empty()) { ErrorOr> IndexOrErr = @@ -202,6 +208,14 @@ return false; } Index = std::move(IndexOrErr.get()); + + // Linkage Promotion and renaming + FunctionImportGlobalProcessing ThinLTOProcessing(*M, *Index, + &GlobalsToImport); + if (ThinLTOProcessing.run()) + return true; + for (auto *GV : ThinLTOProcessing.getNewExportedValues()) + GlobalsToImport.insert(GV); } // Save the mapping of value ids to temporary metadata created when @@ -211,11 +225,8 @@ if (!TempMDVals) TempMDVals = llvm::make_unique>(); - // Link in the specified function. - DenseSet FunctionsToImport; - FunctionsToImport.insert(F); - if (L.linkInModule(std::move(M), Linker::Flags::None, Index.get(), - &FunctionsToImport, TempMDVals.get())) + if (L.linkInModule(std::move(M), Linker::Flags::None, &GlobalsToImport, + TempMDVals.get())) return false; } @@ -271,12 +282,17 @@ return false; } Index = std::move(IndexOrErr.get()); + + // Promotion + FunctionImportGlobalProcessing ThinLTOProcessing(*M, *Index); + if (ThinLTOProcessing.run()) + return true; } if (Verbose) errs() << "Linking in '" << File << "'\n"; - if (L.linkInModule(std::move(M), ApplicableFlags, Index.get())) + if (L.linkInModule(std::move(M), ApplicableFlags)) return false; // All linker flags apply to linking of subsequent files. ApplicableFlags = Flags;