summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/LTO/LTOCodeGenerator.h21
-rw-r--r--llvm/lib/LTO/LTOCodeGenerator.cpp42
-rw-r--r--llvm/test/LTO/X86/restore-externals.ll24
3 files changed, 85 insertions, 2 deletions
diff --git a/llvm/include/llvm/LTO/LTOCodeGenerator.h b/llvm/include/llvm/LTO/LTOCodeGenerator.h
index 3820b211a38..b40aa5cb87d 100644
--- a/llvm/include/llvm/LTO/LTOCodeGenerator.h
+++ b/llvm/include/llvm/LTO/LTOCodeGenerator.h
@@ -39,6 +39,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/GlobalValue.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include <string>
@@ -47,7 +48,6 @@
namespace llvm {
class LLVMContext;
class DiagnosticInfo;
- class GlobalValue;
class Linker;
class Mangler;
class MemoryBuffer;
@@ -86,6 +86,22 @@ struct LTOCodeGenerator {
void setShouldInternalize(bool Value) { ShouldInternalize = Value; }
void setShouldEmbedUselists(bool Value) { ShouldEmbedUselists = Value; }
+ /// Restore linkage of globals
+ ///
+ /// When set, the linkage of globals will be restored prior to code
+ /// generation. That is, a global symbol that had external linkage prior to
+ /// LTO will be emitted with external linkage again; and a local will remain
+ /// local. Note that this option only affects the end result - globals may
+ /// still be internalized in the process of LTO and may be modified and/or
+ /// deleted where legal.
+ ///
+ /// The default behavior will internalize globals (unless on the preserve
+ /// list) and, if parallel code generation is enabled, will externalize
+ /// all locals.
+ void setShouldRestoreGlobalsLinkage(bool Value) {
+ ShouldRestoreGlobalsLinkage = Value;
+ }
+
void addMustPreserveSymbol(StringRef Sym) { MustPreserveSymbols[Sym] = 1; }
/// Pass options to the driver and optimization passes.
@@ -154,6 +170,7 @@ private:
void initializeLTOPasses();
bool compileOptimizedToFile(const char **Name);
+ void restoreLinkageForExternals();
void applyScopeRestrictions();
void applyRestriction(GlobalValue &GV, ArrayRef<StringRef> Libcalls,
std::vector<const char *> &MustPreserveList,
@@ -178,6 +195,7 @@ private:
Reloc::Model RelocModel = Reloc::Default;
StringSet MustPreserveSymbols;
StringSet AsmUndefinedRefs;
+ StringMap<GlobalValue::LinkageTypes> ExternalSymbols;
std::vector<std::string> CodegenOptions;
std::string FeatureStr;
std::string MCpu;
@@ -190,6 +208,7 @@ private:
void *DiagContext = nullptr;
bool ShouldInternalize = true;
bool ShouldEmbedUselists = false;
+ bool ShouldRestoreGlobalsLinkage = false;
TargetMachine::CodeGenFileType FileType = TargetMachine::CGFT_ObjectFile;
};
}
diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp
index 66df23bab1b..70626682d55 100644
--- a/llvm/lib/LTO/LTOCodeGenerator.cpp
+++ b/llvm/lib/LTO/LTOCodeGenerator.cpp
@@ -347,6 +347,12 @@ applyRestriction(GlobalValue &GV,
if (isa<Function>(GV) &&
std::binary_search(Libcalls.begin(), Libcalls.end(), GV.getName()))
AsmUsed.insert(&GV);
+
+ // Record the linkage type of non-local symbols so they can be restored prior
+ // to module splitting.
+ if (ShouldRestoreGlobalsLinkage && !GV.hasAvailableExternallyLinkage() &&
+ !GV.hasLocalLinkage() && GV.hasName())
+ ExternalSymbols.insert(std::make_pair(GV.getName(), GV.getLinkage()));
}
static void findUsedValues(GlobalVariable *LLVMUsed,
@@ -454,6 +460,35 @@ void LTOCodeGenerator::applyScopeRestrictions() {
ScopeRestrictionsDone = true;
}
+/// Restore original linkage for symbols that may have been internalized
+void LTOCodeGenerator::restoreLinkageForExternals() {
+ if (!ShouldInternalize || !ShouldRestoreGlobalsLinkage)
+ return;
+
+ assert(ScopeRestrictionsDone &&
+ "Cannot externalize without internalization!");
+
+ if (ExternalSymbols.empty())
+ return;
+
+ auto externalize = [this](GlobalValue &GV) {
+ if (!GV.hasLocalLinkage() || !GV.hasName())
+ return;
+
+ auto I = ExternalSymbols.find(GV.getName());
+ if (I == ExternalSymbols.end())
+ return;
+
+ GV.setLinkage(I->second);
+ };
+
+ std::for_each(MergedModule->begin(), MergedModule->end(), externalize);
+ std::for_each(MergedModule->global_begin(), MergedModule->global_end(),
+ externalize);
+ std::for_each(MergedModule->alias_begin(), MergedModule->alias_end(),
+ externalize);
+}
+
/// Optimize merged modules using various IPO passes
bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline,
bool DisableGVNLoadPRE,
@@ -504,6 +539,10 @@ bool LTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream *> Out) {
preCodeGenPasses.add(createObjCARCContractPass());
preCodeGenPasses.run(*MergedModule);
+ // Re-externalize globals that may have been internalized to increase scope
+ // for splitting
+ restoreLinkageForExternals();
+
// Do code generation. We need to preserve the module in case the client calls
// writeMergedModules() after compilation, but we only need to allow this at
// parallelism level 1. This is achieved by having splitCodeGen return the
@@ -511,7 +550,8 @@ bool LTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream *> Out) {
// MergedModule.
MergedModule =
splitCodeGen(std::move(MergedModule), Out, MCpu, FeatureStr, Options,
- RelocModel, CodeModel::Default, CGOptLevel, FileType);
+ RelocModel, CodeModel::Default, CGOptLevel, FileType,
+ ShouldRestoreGlobalsLinkage);
return true;
}
diff --git a/llvm/test/LTO/X86/restore-externals.ll b/llvm/test/LTO/X86/restore-externals.ll
new file mode 100644
index 00000000000..05b6d65b47e
--- /dev/null
+++ b/llvm/test/LTO/X86/restore-externals.ll
@@ -0,0 +1,24 @@
+; Check that "internalizedfn" is re-externalized prior to CodeGen when
+; setShouldRestoreGlobalsLinkage is enabled.
+;
+; RUN: llvm-as < %s > %t1
+; RUN: llvm-lto -exported-symbol=preservedfn -restore-linkage -filetype=asm -o - %t1 | FileCheck %s
+;
+; CHECK: .globl internalizedfn
+
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @f()
+
+define void @internalizedfn() noinline {
+entry:
+ call void @f()
+ ret void
+}
+
+define void @preservedfn() {
+entry:
+ call void @internalizedfn()
+ ret void
+}
+
OpenPOWER on IntegriCloud