diff --git a/llvm/include/llvm/Transforms/IPO/FunctionImport.h b/llvm/include/llvm/Transforms/IPO/FunctionImport.h --- a/llvm/include/llvm/Transforms/IPO/FunctionImport.h +++ b/llvm/include/llvm/Transforms/IPO/FunctionImport.h @@ -105,8 +105,10 @@ std::function>(StringRef Identifier)>; /// Create a Function Importer. - FunctionImporter(const ModuleSummaryIndex &Index, ModuleLoaderTy ModuleLoader) - : Index(Index), ModuleLoader(std::move(ModuleLoader)) {} + FunctionImporter(const ModuleSummaryIndex &Index, ModuleLoaderTy ModuleLoader, + bool ClearDSOLocal) + : Index(Index), ModuleLoader(std::move(ModuleLoader)), + ClearDSOLocal(ClearDSOLocal) {} /// Import functions in Module \p M based on the supplied import list. Expected importFunctions(Module &M, const ImportMapTy &ImportList); @@ -117,6 +119,8 @@ /// Factory function to load a Module for a given identifier ModuleLoaderTy ModuleLoader; + + bool ClearDSOLocal; }; /// The function importing pass diff --git a/llvm/include/llvm/Transforms/Utils/FunctionImportUtils.h b/llvm/include/llvm/Transforms/Utils/FunctionImportUtils.h --- a/llvm/include/llvm/Transforms/Utils/FunctionImportUtils.h +++ b/llvm/include/llvm/Transforms/Utils/FunctionImportUtils.h @@ -39,6 +39,8 @@ /// as part of a different backend compilation process. bool HasExportedFunctions = false; + bool ClearDSOLocal; + /// Set of llvm.*used values, in order to validate that we don't try /// to promote any non-renamable values. SmallPtrSet Used; @@ -85,10 +87,11 @@ GlobalValue::LinkageTypes getLinkage(const GlobalValue *SGV, bool DoPromote); public: - FunctionImportGlobalProcessing( - Module &M, const ModuleSummaryIndex &Index, - SetVector *GlobalsToImport = nullptr) - : M(M), ImportIndex(Index), GlobalsToImport(GlobalsToImport) { + FunctionImportGlobalProcessing(Module &M, const ModuleSummaryIndex &Index, + SetVector *GlobalsToImport, + bool ClearDSOLocal) + : M(M), ImportIndex(Index), GlobalsToImport(GlobalsToImport), + ClearDSOLocal(ClearDSOLocal) { // If we have a ModuleSummaryIndex 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 @@ -110,7 +113,7 @@ /// Perform in-place global value handling on the given Module for /// exported local functions renamed and promoted for ThinLTO. bool renameModuleForThinLTO( - Module &M, const ModuleSummaryIndex &Index, + Module &M, const ModuleSummaryIndex &Index, bool DropDSOLocal, SetVector *GlobalsToImport = nullptr); /// Compute synthetic function entry counts. diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -519,7 +519,10 @@ if (Conf.PreOptModuleHook && !Conf.PreOptModuleHook(Task, Mod)) return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); - renameModuleForThinLTO(Mod, CombinedIndex); + bool ClearDSOLocal = TM->getTargetTriple().isOSBinFormatELF() && + TM->getRelocationModel() != Reloc::Static && + Mod.getPIELevel() == PIELevel::Default; + renameModuleForThinLTO(Mod, CombinedIndex, ClearDSOLocal); dropDeadSymbols(Mod, DefinedGlobals, CombinedIndex); @@ -545,7 +548,7 @@ /*IsImporting*/ true); }; - FunctionImporter Importer(CombinedIndex, ModuleLoader); + FunctionImporter Importer(CombinedIndex, ModuleLoader, ClearDSOLocal); if (Error Err = Importer.importFunctions(Mod, ImportList).takeError()) return Err; diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp --- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -151,7 +151,7 @@ } static void promoteModule(Module &TheModule, const ModuleSummaryIndex &Index) { - if (renameModuleForThinLTO(TheModule, Index)) + if (renameModuleForThinLTO(TheModule, Index, false)) report_fatal_error("renameModuleForThinLTO failed"); } @@ -211,7 +211,7 @@ /*Lazy=*/true, /*IsImporting*/ true); }; - FunctionImporter Importer(Index, Loader); + FunctionImporter Importer(Index, Loader, false); Expected Result = Importer.importFunctions(TheModule, ImportList); if (!Result) { handleAllErrors(Result.takeError(), [&](ErrorInfoBase &EIB) { diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp --- a/llvm/lib/Transforms/IPO/FunctionImport.cpp +++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -1231,7 +1231,8 @@ UpgradeDebugInfo(*SrcModule); // Link in the specified functions. - if (renameModuleForThinLTO(*SrcModule, Index, &GlobalsToImport)) + if (renameModuleForThinLTO(*SrcModule, Index, ClearDSOLocal, + &GlobalsToImport)) return true; if (PrintImports) { @@ -1300,7 +1301,7 @@ // Next we need to promote to global scope and rename any local values that // are potentially exported to other modules. - if (renameModuleForThinLTO(M, *Index, nullptr)) { + if (renameModuleForThinLTO(M, *Index, false, nullptr)) { errs() << "Error renaming module\n"; return false; } @@ -1309,7 +1310,7 @@ auto ModuleLoader = [&M](StringRef Identifier) { return loadFile(std::string(Identifier), M.getContext()); }; - FunctionImporter Importer(*Index, ModuleLoader); + FunctionImporter Importer(*Index, ModuleLoader, false); Expected Result = Importer.importFunctions(M, ImportList); // FIXME: Probably need to propagate Errors through the pass manager. diff --git a/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp b/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp --- a/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp +++ b/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp @@ -212,13 +212,6 @@ } } } - // Check the summaries to see if the symbol gets resolved to a known local - // definition. - if (VI && VI.isDSOLocal()) { - GV.setDSOLocal(true); - if (GV.hasDLLImportStorageClass()) - GV.setDLLStorageClass(GlobalValue::DefaultStorageClass); - } } // We should always have a ValueInfo (i.e. GV in index) for definitions when @@ -280,6 +273,16 @@ } else GV.setLinkage(getLinkage(&GV, /* DoPromote */ false)); + if (ClearDSOLocal && GV.isDeclarationForLinker() && !GV.isImplicitDSOLocal()) + GV.setDSOLocal(false); + else if (VI && VI.isDSOLocal()) { + // If all summaries are dso_local, symbol gets resolved to a known local + // definition. + GV.setDSOLocal(true); + if (GV.hasDLLImportStorageClass()) + GV.setDLLStorageClass(GlobalValue::DefaultStorageClass); + } + // Remove functions imported as available externally defs from comdats, // as this is a declaration for the linker, and will be dropped eventually. // It is illegal for comdats to contain declarations. @@ -319,7 +322,9 @@ } bool llvm::renameModuleForThinLTO(Module &M, const ModuleSummaryIndex &Index, + bool ClearDSOLocal, SetVector *GlobalsToImport) { - FunctionImportGlobalProcessing ThinLTOProcessing(M, Index, GlobalsToImport); + FunctionImportGlobalProcessing ThinLTOProcessing(M, Index, GlobalsToImport, + ClearDSOLocal); return ThinLTOProcessing.run(); } diff --git a/llvm/test/LTO/Resolution/X86/local-def-dllimport.ll b/llvm/test/LTO/Resolution/X86/local-def-dllimport.ll --- a/llvm/test/LTO/Resolution/X86/local-def-dllimport.ll +++ b/llvm/test/LTO/Resolution/X86/local-def-dllimport.ll @@ -13,9 +13,7 @@ $g = comdat any @g = global i8 42, comdat, !type !0 -; CHECK: define -; CHECK-NOT: dllimport -; CHECK-SAME: @f +; CHECK: define available_externally dllimport i8* @f() define available_externally dllimport i8* @f() { ret i8* @g } diff --git a/llvm/test/ThinLTO/X86/funcimport_alwaysinline.ll b/llvm/test/ThinLTO/X86/funcimport_alwaysinline.ll --- a/llvm/test/ThinLTO/X86/funcimport_alwaysinline.ll +++ b/llvm/test/ThinLTO/X86/funcimport_alwaysinline.ll @@ -11,7 +11,7 @@ ; foo() being always_inline should be imported irrespective of the ; instruction limit -; CHECK1: define available_externally dso_local void @foo() +; CHECK1: define available_externally void @foo() target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/ThinLTO/X86/index-const-prop-alias.ll b/llvm/test/ThinLTO/X86/index-const-prop-alias.ll --- a/llvm/test/ThinLTO/X86/index-const-prop-alias.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop-alias.ll @@ -16,15 +16,15 @@ ; RUN: llvm-dis %t5.1.3.import.bc -o - | FileCheck %s --check-prefix=PRESERVED ; We currently don't support importing aliases -; IMPORT: @g.alias = external dso_local global i32 +; IMPORT: @g.alias = external global i32 ; IMPORT-NEXT: @g = internal global i32 42, align 4 #0 ; IMPORT: attributes #0 = { "thinlto-internalize" } ; CODEGEN: define dso_local i32 @main ; CODEGEN-NEXT: ret i32 42 -; PRESERVED: @g.alias = external dso_local global i32 -; PRESERVED-NEXT: @g = available_externally dso_local global i32 42, align 4 +; PRESERVED: @g.alias = external global i32 +; PRESERVED-NEXT: @g = available_externally global i32 42, align 4 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/ThinLTO/X86/index-const-prop-comdat.ll b/llvm/test/ThinLTO/X86/index-const-prop-comdat.ll --- a/llvm/test/ThinLTO/X86/index-const-prop-comdat.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop-comdat.ll @@ -4,7 +4,7 @@ ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s ; Comdats are not internalized even if they are read only. -; CHECK: @g = available_externally dso_local global i32 42 +; CHECK: @g = available_externally global i32 42 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/ThinLTO/X86/index-const-prop-dead.ll b/llvm/test/ThinLTO/X86/index-const-prop-dead.ll --- a/llvm/test/ThinLTO/X86/index-const-prop-dead.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop-dead.ll @@ -6,7 +6,7 @@ ; Dead globals are converted to declarations by ThinLTO in dropDeadSymbols ; If we try to internalize such we'll get a broken module. -; CHECK: @g = external dso_local global i32 +; CHECK: @g = external global i32 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/ThinLTO/X86/index-const-prop-full-lto.ll b/llvm/test/ThinLTO/X86/index-const-prop-full-lto.ll --- a/llvm/test/ThinLTO/X86/index-const-prop-full-lto.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop-full-lto.ll @@ -8,7 +8,7 @@ ; All references from functions in full LTO module are not constant. ; We cannot internalize @g -; CHECK: @g = available_externally dso_local global i32 42 +; CHECK: @g = available_externally global i32 42 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/ThinLTO/X86/index-const-prop-gvref.ll b/llvm/test/ThinLTO/X86/index-const-prop-gvref-pie.ll copy from llvm/test/ThinLTO/X86/index-const-prop-gvref.ll copy to llvm/test/ThinLTO/X86/index-const-prop-gvref-pie.ll --- a/llvm/test/ThinLTO/X86/index-const-prop-gvref.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop-gvref-pie.ll @@ -1,15 +1,11 @@ +;; The same as index-const-prop-gvref.ll, except for PIE. ; RUN: opt -module-summary %s -o %t1.bc ; RUN: opt -module-summary %p/Inputs/index-const-prop-gvref.ll -o %t2.bc ; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,b,pl -r=%t2.bc,a,pl \ -; RUN: %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,a, -r=%t1.bc,b, -o %t3 -; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=SRC +; RUN: %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,a, -r=%t1.bc,b, -o %t3 ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s --check-prefix=DEST -; No variable in the source module should have been internalized -; SRC: @b = dso_local global i32* @a -; SRC-NEXT: @a = dso_local global i32 42 - -; We can't internalize globals referenced by other live globals +;; For PIE, keep dso_local for declarations to enable direct access. ; DEST: @b = external dso_local global i32* ; DEST-NEXT: @a = available_externally dso_local global i32 42, align 4 @@ -20,8 +16,13 @@ @b = external global i32* define i32 @main() { - %p = load i32*, i32** @b, align 8 + %p = load i32*, i32** @b, align 8 store i32 33, i32* %p, align 4 %v = load i32, i32* @a, align 4 ret i32 %v } + +!llvm.module.flags = !{!0} + +!0 = !{i32 7, !"PIE Level", i32 2} +!1 = !{i32 7, !"PIC Level", i32 2} diff --git a/llvm/test/ThinLTO/X86/index-const-prop-gvref.ll b/llvm/test/ThinLTO/X86/index-const-prop-gvref.ll --- a/llvm/test/ThinLTO/X86/index-const-prop-gvref.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop-gvref.ll @@ -1,17 +1,25 @@ ; RUN: opt -module-summary %s -o %t1.bc ; RUN: opt -module-summary %p/Inputs/index-const-prop-gvref.ll -o %t2.bc -; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,b,pl -r=%t2.bc,a,pl \ -; RUN: %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,a, -r=%t1.bc,b, -o %t3 +; RUN: llvm-lto2 run -relocation-model=static -save-temps %t2.bc -r=%t2.bc,b,pl -r=%t2.bc,a,pl \ +; RUN: %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,a, -r=%t1.bc,b, -o %t3 ; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=SRC ; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s --check-prefix=DEST +;; When producing an ELF DSO, drop dso_local for declarations to avoid direct access. +; RUN: llvm-lto2 run -relocation-model=pic -save-temps %t2.bc -r=%t2.bc,b,pl -r=%t2.bc,a,pl \ +; RUN: %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,a, -r=%t1.bc,b, -o %t4 +; RUN: llvm-dis %t4.1.3.import.bc -o - | FileCheck %s --check-prefix=SRC +; RUN: llvm-dis %t4.2.3.import.bc -o - | FileCheck %s --check-prefix=DEST_DSO + ; No variable in the source module should have been internalized ; SRC: @b = dso_local global i32* @a ; SRC-NEXT: @a = dso_local global i32 42 ; We can't internalize globals referenced by other live globals -; DEST: @b = external dso_local global i32* -; DEST-NEXT: @a = available_externally dso_local global i32 42, align 4 +; DEST: @b = external dso_local global i32* +; DEST-NEXT: @a = available_externally dso_local global i32 42, align 4 +; DEST_DSO: @b = external global i32* +; DEST_DSO-NEXT: @a = available_externally global i32 42, align 4 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/ThinLTO/X86/index-const-prop-ldst.ll b/llvm/test/ThinLTO/X86/index-const-prop-ldst.ll --- a/llvm/test/ThinLTO/X86/index-const-prop-ldst.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop-ldst.ll @@ -5,7 +5,7 @@ ; The 'store' instruction in @main should prevent internalization ; even when there is 'load' instruction before it. -; CHECK: @g = available_externally dso_local global i32 42 +; CHECK: @g = available_externally global i32 42 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/ThinLTO/X86/index-const-prop-linkage.ll b/llvm/test/ThinLTO/X86/index-const-prop-linkage.ll --- a/llvm/test/ThinLTO/X86/index-const-prop-linkage.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop-linkage.ll @@ -11,7 +11,7 @@ ; - reference from @llvm.used ; CHECK: @llvm.used = appending global [1 x i32*] [i32* @g2] ; CHECK-NEXT: @g1 = external dso_local global i32, align 4 -; CHECK-NEXT: @g2 = available_externally dso_local global i32 42, align 4 +; CHECK-NEXT: @g2 = available_externally global i32 42, align 4 ; CHECK-NEXT: @g3 = available_externally global i32 42, align 4 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" diff --git a/llvm/test/ThinLTO/X86/index-const-prop2.ll b/llvm/test/ThinLTO/X86/index-const-prop2.ll --- a/llvm/test/ThinLTO/X86/index-const-prop2.ll +++ b/llvm/test/ThinLTO/X86/index-const-prop2.ll @@ -68,7 +68,7 @@ ; CODEGEN: i32 @main() ; CODEGEN-NEXT: ret i32 3 -; IMPORT2: @gBar = available_externally dso_local local_unnamed_addr global i32 2, align 4 +; IMPORT2: @gBar = available_externally local_unnamed_addr global i32 2, align 4 ; CODEGEN2: i32 @main2 ; CODEGEN2-NEXT: %1 = tail call i32 @rand() diff --git a/llvm/tools/llvm-link/llvm-link.cpp b/llvm/tools/llvm-link/llvm-link.cpp --- a/llvm/tools/llvm-link/llvm-link.cpp +++ b/llvm/tools/llvm-link/llvm-link.cpp @@ -266,7 +266,7 @@ auto CachedModuleLoader = [&](StringRef Identifier) { return ModuleLoaderCache.takeModule(std::string(Identifier)); }; - FunctionImporter Importer(*Index, CachedModuleLoader); + FunctionImporter Importer(*Index, CachedModuleLoader, false); ExitOnErr(Importer.importFunctions(DestModule, ImportList)); return true; @@ -313,7 +313,7 @@ } // Promotion - if (renameModuleForThinLTO(*M, *Index)) + if (renameModuleForThinLTO(*M, *Index, false)) return true; }