diff options
-rw-r--r-- | clang/include/clang/CodeGen/CodeGenAction.h | 3 | ||||
-rw-r--r-- | clang/include/clang/Frontend/CodeGenOptions.h | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenAction.cpp | 31 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 4 | ||||
-rw-r--r-- | llvm/include/llvm/Linker/Linker.h | 14 | ||||
-rw-r--r-- | llvm/lib/Linker/LinkModules.cpp | 46 | ||||
-rw-r--r-- | llvm/test/Linker/Inputs/linkage.d.ll | 5 | ||||
-rw-r--r-- | llvm/test/Linker/link-flags.ll | 6 | ||||
-rw-r--r-- | llvm/tools/llvm-link/llvm-link.cpp | 23 |
9 files changed, 100 insertions, 34 deletions
diff --git a/clang/include/clang/CodeGen/CodeGenAction.h b/clang/include/clang/CodeGen/CodeGenAction.h index 65eda5bb98e..5a18a9de030 100644 --- a/clang/include/clang/CodeGen/CodeGenAction.h +++ b/clang/include/clang/CodeGen/CodeGenAction.h @@ -36,6 +36,9 @@ private: /// function ourselves. bool PropagateAttrs; + /// If true, we use LLVM module internalizer. + bool Internalize; + /// Bitwise combination of llvm::LinkerFlags used when we link the module. unsigned LinkFlags; }; diff --git a/clang/include/clang/Frontend/CodeGenOptions.h b/clang/include/clang/Frontend/CodeGenOptions.h index a21abac24b9..f8f32666c53 100644 --- a/clang/include/clang/Frontend/CodeGenOptions.h +++ b/clang/include/clang/Frontend/CodeGenOptions.h @@ -137,6 +137,8 @@ public: /// our CodeGenOptions, much as we set attrs on functions that we generate /// ourselves. bool PropagateAttrs = false; + /// If true, we use LLVM module internalizer. + bool Internalize = false; /// Bitwise combination of llvm::Linker::Flags, passed to the LLVM linker. unsigned LinkFlags = 0; }; diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index c7604145619..20a61f33f94 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -28,6 +28,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/GlobalValue.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" @@ -38,6 +39,8 @@ #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/Transforms/IPO/Internalize.h" + #include <memory> using namespace clang; using namespace llvm; @@ -168,8 +171,22 @@ namespace clang { Gen->CGM().AddDefaultFnAttrs(F); CurLinkModule = LM.Module.get(); - if (Linker::linkModules(*getModule(), std::move(LM.Module), - LM.LinkFlags)) + + bool Err; + if (LM.Internalize) { + Err = Linker::linkModules( + *getModule(), std::move(LM.Module), LM.LinkFlags, + [](llvm::Module &M, const llvm::StringSet<> &GVS) { + internalizeModule(M, [&M, &GVS](const llvm::GlobalValue &GV) { + return !GV.hasName() || (GVS.count(GV.getName()) == 0); + }); + }); + } else { + Err = Linker::linkModules(*getModule(), std::move(LM.Module), + LM.LinkFlags); + } + + if (Err) return true; } return false; // success @@ -319,7 +336,7 @@ namespace clang { void OptimizationFailureHandler( const llvm::DiagnosticInfoOptimizationFailure &D); }; - + void BackendConsumer::anchor() {} } @@ -388,7 +405,7 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, // code. if (LocCookie.isValid()) { Diags.Report(LocCookie, DiagID).AddString(Message); - + if (D.getLoc().isValid()) { DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here); // Convert the SMDiagnostic ranges into SourceRange and attach them @@ -401,7 +418,7 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, } return; } - + // Otherwise, report the backend issue as occurring in the generated .s file. // If Loc is invalid, we still need to report the issue, it just gets no // location info. @@ -815,8 +832,8 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { LinkModules.clear(); return nullptr; } - LinkModules.push_back( - {std::move(ModuleOrErr.get()), F.PropagateAttrs, F.LinkFlags}); + LinkModules.push_back({std::move(ModuleOrErr.get()), F.PropagateAttrs, + F.Internalize, F.LinkFlags}); } CoverageSourceInfo *CoverageInfo = nullptr; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 598af20864b..23529749099 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -727,11 +727,11 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, CodeGenOptions::BitcodeFileToLink F; F.Filename = A->getValue(); if (A->getOption().matches(OPT_mlink_cuda_bitcode)) { - F.LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded | - llvm::Linker::Flags::InternalizeLinkedSymbols; + F.LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded; // When linking CUDA bitcode, propagate function attributes so that // e.g. libdevice gets fast-math attrs if we're building with fast-math. F.PropagateAttrs = true; + F.Internalize = true; } Opts.LinkBitcodeFiles.push_back(F); } diff --git a/llvm/include/llvm/Linker/Linker.h b/llvm/include/llvm/Linker/Linker.h index f203d349585..628e0112bd9 100644 --- a/llvm/include/llvm/Linker/Linker.h +++ b/llvm/include/llvm/Linker/Linker.h @@ -10,6 +10,7 @@ #ifndef LLVM_LINKER_LINKER_H #define LLVM_LINKER_LINKER_H +#include "llvm/ADT/StringSet.h" #include "llvm/Linker/IRMover.h" namespace llvm { @@ -29,7 +30,6 @@ public: None = 0, OverrideFromSrc = (1 << 0), LinkOnlyNeeded = (1 << 1), - InternalizeLinkedSymbols = (1 << 2), }; Linker(Module &M); @@ -39,11 +39,19 @@ public: /// Passing OverrideSymbols as true will have symbols from Src /// shadow those in the Dest. /// + /// Passing InternalizeCallback will have the linker call the function with + /// the new module and a list of global value names to be internalized by the + /// callback. + /// /// Returns true on error. - bool linkInModule(std::unique_ptr<Module> Src, unsigned Flags = Flags::None); + bool linkInModule(std::unique_ptr<Module> Src, unsigned Flags = Flags::None, + std::function<void(Module &, const StringSet<> &)> + InternalizeCallback = {}); static bool linkModules(Module &Dest, std::unique_ptr<Module> Src, - unsigned Flags = Flags::None); + unsigned Flags = Flags::None, + std::function<void(Module &, const StringSet<> &)> + InternalizeCallback = {}); }; } // End llvm namespace diff --git a/llvm/lib/Linker/LinkModules.cpp b/llvm/lib/Linker/LinkModules.cpp index f11fd54f4af..c0ce4bf76b9 100644 --- a/llvm/lib/Linker/LinkModules.cpp +++ b/llvm/lib/Linker/LinkModules.cpp @@ -14,7 +14,6 @@ #include "LinkDiagnosticInfo.h" #include "llvm-c/Linker.h" #include "llvm/ADT/SetVector.h" -#include "llvm/ADT/StringSet.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/GlobalValue.h" @@ -33,11 +32,18 @@ class ModuleLinker { std::unique_ptr<Module> SrcM; SetVector<GlobalValue *> ValuesToLink; - StringSet<> Internalize; /// For symbol clashes, prefer those from Src. unsigned Flags; + /// List of global value names that should be internalized. + StringSet<> Internalize; + + /// Function that will perform the actual internalization. The reason for a + /// callback is that the linker cannot call internalizeModule without + /// creating a circular dependency between IPO and the linker. + std::function<void(Module &, const StringSet<> &)> InternalizeCallback; + /// Used as the callback for lazy linking. /// The mover has just hit GV and we have to decide if it, and other members /// of the same comdat, should be linked. Every member to be linked is passed @@ -46,9 +52,6 @@ class ModuleLinker { bool shouldOverrideFromSrc() { return Flags & Linker::OverrideFromSrc; } bool shouldLinkOnlyNeeded() { return Flags & Linker::LinkOnlyNeeded; } - bool shouldInternalizeLinkedSymbols() { - return Flags & Linker::InternalizeLinkedSymbols; - } bool shouldLinkFromSource(bool &LinkFromSrc, const GlobalValue &Dest, const GlobalValue &Src); @@ -104,8 +107,11 @@ class ModuleLinker { bool linkIfNeeded(GlobalValue &GV); public: - ModuleLinker(IRMover &Mover, std::unique_ptr<Module> SrcM, unsigned Flags) - : Mover(Mover), SrcM(std::move(SrcM)), Flags(Flags) {} + ModuleLinker(IRMover &Mover, std::unique_ptr<Module> SrcM, unsigned Flags, + std::function<void(Module &, const StringSet<> &)> + InternalizeCallback = {}) + : Mover(Mover), SrcM(std::move(SrcM)), Flags(Flags), + InternalizeCallback(std::move(InternalizeCallback)) {} bool run(); }; @@ -383,7 +389,7 @@ void ModuleLinker::addLazyFor(GlobalValue &GV, const IRMover::ValueAdder &Add) { !shouldLinkOnlyNeeded()) return; - if (shouldInternalizeLinkedSymbols()) + if (InternalizeCallback) Internalize.insert(GV.getName()); Add(GV); @@ -397,7 +403,7 @@ void ModuleLinker::addLazyFor(GlobalValue &GV, const IRMover::ValueAdder &Add) { return; if (!LinkFromSrc) continue; - if (shouldInternalizeLinkedSymbols()) + if (InternalizeCallback) Internalize.insert(GV2->getName()); Add(*GV2); } @@ -526,7 +532,7 @@ bool ModuleLinker::run() { } } - if (shouldInternalizeLinkedSymbols()) { + if (InternalizeCallback) { for (GlobalValue *GV : ValuesToLink) Internalize.insert(GV->getName()); } @@ -547,18 +553,19 @@ bool ModuleLinker::run() { if (HasErrors) return true; - for (auto &P : Internalize) { - GlobalValue *GV = DstM.getNamedValue(P.first()); - GV->setLinkage(GlobalValue::InternalLinkage); - } + if (InternalizeCallback) + InternalizeCallback(DstM, Internalize); return false; } Linker::Linker(Module &M) : Mover(M) {} -bool Linker::linkInModule(std::unique_ptr<Module> Src, unsigned Flags) { - ModuleLinker ModLinker(Mover, std::move(Src), Flags); +bool Linker::linkInModule( + std::unique_ptr<Module> Src, unsigned Flags, + std::function<void(Module &, const StringSet<> &)> InternalizeCallback) { + ModuleLinker ModLinker(Mover, std::move(Src), Flags, + std::move(InternalizeCallback)); return ModLinker.run(); } @@ -571,10 +578,11 @@ bool Linker::linkInModule(std::unique_ptr<Module> Src, unsigned Flags) { /// true is returned and ErrorMsg (if not null) is set to indicate the problem. /// Upon failure, the Dest module could be in a modified state, and shouldn't be /// relied on to be consistent. -bool Linker::linkModules(Module &Dest, std::unique_ptr<Module> Src, - unsigned Flags) { +bool Linker::linkModules( + Module &Dest, std::unique_ptr<Module> Src, unsigned Flags, + std::function<void(Module &, const StringSet<> &)> InternalizeCallback) { Linker L(Dest); - return L.linkInModule(std::move(Src), Flags); + return L.linkInModule(std::move(Src), Flags, std::move(InternalizeCallback)); } //===----------------------------------------------------------------------===// diff --git a/llvm/test/Linker/Inputs/linkage.d.ll b/llvm/test/Linker/Inputs/linkage.d.ll new file mode 100644 index 00000000000..aaf010d3885 --- /dev/null +++ b/llvm/test/Linker/Inputs/linkage.d.ll @@ -0,0 +1,5 @@ +@Y = global i8 42 + +define i64 @foo() { ret i64 7 } + +@llvm.used = appending global [2 x i8*] [i8* @Y, i8* bitcast (i64 ()* @foo to i8*)], section "llvm.metadata" diff --git a/llvm/test/Linker/link-flags.ll b/llvm/test/Linker/link-flags.ll index c901b699575..1a57e8aa4d2 100644 --- a/llvm/test/Linker/link-flags.ll +++ b/llvm/test/Linker/link-flags.ll @@ -2,12 +2,15 @@ ; RUN: llvm-link -S -only-needed %S/Inputs/linkage.b.ll %S/Inputs/linkage.c.ll | FileCheck %s -check-prefix=B -check-prefix=C -check-prefix=CN ; RUN: llvm-link -S -internalize %S/Inputs/linkage.b.ll %S/Inputs/linkage.c.ll | FileCheck %s -check-prefix=B -check-prefix=CI ; RUN: llvm-link -S -internalize -only-needed %S/Inputs/linkage.b.ll %S/Inputs/linkage.c.ll | FileCheck %s -check-prefix=B -check-prefix=CN +; RUN: llvm-link -S -internalize %S/Inputs/linkage.b.ll %S/Inputs/linkage.c.ll %S/Inputs/linkage.d.ll | FileCheck %s -check-prefix=B -check-prefix=DI C-LABEL: @X = global i32 5 CI-LABEL: @X = internal global i32 5 CU-LABEL:@U = global i32 6 CI-LABEL:@U = internal global i32 6 CN-NOT:@U +DI-LABEL: @Y = global i8 42 +DI-LABEL: @llvm.used = appending global [2 x i8*] [i8* @Y, i8* bitcast (i64 ()* @foo to i8*)], section "llvm.metadata" B-LABEL: define void @bar() { @@ -17,3 +20,6 @@ CI-LABEL: define internal i32 @foo() CU-LABEL:define i32 @unused() { CI-LABEL:define internal i32 @unused() { CN-NOT:@unused() + +DI-LABEL: define internal i32 @foo.6() +DI-LABEL: define i64 @foo() diff --git a/llvm/tools/llvm-link/llvm-link.cpp b/llvm/tools/llvm-link/llvm-link.cpp index e89696e7e7c..6cb647d48eb 100644 --- a/llvm/tools/llvm-link/llvm-link.cpp +++ b/llvm/tools/llvm-link/llvm-link.cpp @@ -34,6 +34,7 @@ #include "llvm/Support/SystemUtils.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Transforms/IPO/FunctionImport.h" +#include "llvm/Transforms/IPO/Internalize.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include <memory> @@ -272,6 +273,8 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L, unsigned Flags) { // Filter out flags that don't apply to the first file we load. unsigned ApplicableFlags = Flags & Linker::Flags::OverrideFromSrc; + // Similar to some flags, internalization doesn't apply to the first file. + bool InternalizeLinkedSymbols = false; for (const auto &File : Files) { std::unique_ptr<Module> M = loadFile(argv0, File, Context); if (!M.get()) { @@ -311,8 +314,24 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L, if (Verbose) errs() << "Linking in '" << File << "'\n"; - if (L.linkInModule(std::move(M), ApplicableFlags)) + bool Err = false; + if (InternalizeLinkedSymbols) { + Err = L.linkInModule( + std::move(M), ApplicableFlags, [](Module &M, const StringSet<> &GVS) { + internalizeModule(M, [&M, &GVS](const GlobalValue &GV) { + return !GV.hasName() || (GVS.count(GV.getName()) == 0); + }); + }); + } else { + Err = L.linkInModule(std::move(M), ApplicableFlags); + } + + if (Err) return false; + + // Internalization applies to linking of subsequent files. + InternalizeLinkedSymbols = Internalize; + // All linker flags apply to linking of subsequent files. ApplicableFlags = Flags; } @@ -340,8 +359,6 @@ int main(int argc, char **argv) { Linker L(*Composite); unsigned Flags = Linker::Flags::None; - if (Internalize) - Flags |= Linker::Flags::InternalizeLinkedSymbols; if (OnlyNeeded) Flags |= Linker::Flags::LinkOnlyNeeded; |