[LTO] Support LLVM LTO for IRGen and frontend

This commit adds -lto flag for frontend to enable LTO at LLVM level.
When -lto=llvm given, compiler emits LLVM bitcode file instead of object
file and adds index summary for LTO.
In addition for ELF format, emit llvm.dependent-libraries section to
embed auto linking information
This commit is contained in:
Yuta Saito
2020-06-17 18:59:48 +09:00
parent 3da8595cd5
commit 20bc0af42b
14 changed files with 322 additions and 61 deletions

View File

@@ -1108,8 +1108,6 @@ llvm::SmallString<32> getTargetDependentLibraryOption(const llvm::Triple &T,
}
void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
llvm::LLVMContext &ctx = Module.getContext();
// The debugger gets the autolink information directly from
// the LinkLibraries of the module, so there's no reason to
// emit it into the IR of debugger expressions.
@@ -1118,10 +1116,7 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
switch (linkLib.getKind()) {
case LibraryKind::Library: {
llvm::SmallString<32> opt =
getTargetDependentLibraryOption(Triple, linkLib.getName());
AutolinkEntries.push_back(
llvm::MDNode::get(ctx, llvm::MDString::get(ctx, opt)));
AutolinkEntries.emplace_back(linkLib);
break;
}
case LibraryKind::Framework: {
@@ -1130,12 +1125,7 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
if (std::find(frameworks.begin(), frameworks.end(), linkLib.getName())
!= frameworks.end())
return;
llvm::Metadata *args[] = {
llvm::MDString::get(ctx, "-framework"),
llvm::MDString::get(ctx, linkLib.getName())
};
AutolinkEntries.push_back(llvm::MDNode::get(ctx, args));
AutolinkEntries.emplace_back(linkLib);
break;
}
}
@@ -1205,38 +1195,132 @@ static bool isFirstObjectFileInModule(IRGenModule &IGM) {
return containingModule->getFiles().front() == file;
}
void IRGenModule::emitAutolinkInfo() {
// Collect the linker options already in the module (from ClangCodeGen).
static bool
doesTargetAutolinkUsingAutolinkExtract(const SwiftTargetInfo &TargetInfo,
const llvm::Triple &Triple) {
if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF && !Triple.isPS4())
return true;
if (TargetInfo.OutputObjectFormat == llvm::Triple::Wasm)
return true;
if (Triple.isOSCygMing())
return true;
return false;
}
namespace {
struct AutolinkKind {
enum ValueTy {
LLVMLinkerOptions,
LLVMDependentLibraries,
SwiftAutoLinkExtract,
};
ValueTy Value;
AutolinkKind(ValueTy value) : Value(value) {}
AutolinkKind(const AutolinkKind &kind) : Value(kind.Value) {}
StringRef getSectionNameMetadata();
template <typename Vector, typename Set>
void collectEntriesFromLibraries(llvm::SetVector<llvm::MDNode *, Vector, Set> &Entries,
ArrayRef<LinkLibrary> AutolinkEntries,
IRGenModule &IGM);
template <typename Vector, typename Set>
void writeEntries(llvm::SetVector<llvm::MDNode *, Vector, Set> Entries,
llvm::NamedMDNode *Metadata, IRGenModule &IGM);
static AutolinkKind create(const SwiftTargetInfo &TargetInfo,
llvm::Triple Triple, IRGenLLVMLTOKind LLVMLTOKind);
};
} // anonymous namespace
StringRef AutolinkKind::getSectionNameMetadata() {
// FIXME: This constant should be vended by LLVM somewhere.
auto *Metadata = Module.getOrInsertNamedMetadata("llvm.linker.options");
for (llvm::MDNode *LinkOption : Metadata->operands())
AutolinkEntries.push_back(LinkOption);
switch (Value) {
case AutolinkKind::LLVMDependentLibraries:
return "llvm.dependent-libraries";
case AutolinkKind::LLVMLinkerOptions:
case AutolinkKind::SwiftAutoLinkExtract:
return "llvm.linker.options";
}
// Remove duplicates.
llvm::SmallPtrSet<llvm::MDNode *, 4> knownAutolinkEntries;
AutolinkEntries.erase(std::remove_if(AutolinkEntries.begin(),
AutolinkEntries.end(),
[&](llvm::MDNode *entry) -> bool {
return !knownAutolinkEntries.insert(
entry).second;
}),
AutolinkEntries.end());
llvm_unreachable("Unhandled AutolinkKind in switch.");
}
const bool AutolinkExtractRequired =
(TargetInfo.OutputObjectFormat == llvm::Triple::ELF && !Triple.isPS4()) ||
TargetInfo.OutputObjectFormat == llvm::Triple::Wasm ||
Triple.isOSCygMing();
template <typename Vector, typename Set>
void AutolinkKind::collectEntriesFromLibraries(
llvm::SetVector<llvm::MDNode *, Vector, Set> &Entries,
ArrayRef<LinkLibrary> AutolinkEntries, IRGenModule &IGM) {
llvm::LLVMContext &ctx = IGM.getLLVMContext();
if (!AutolinkExtractRequired) {
switch (Value) {
case AutolinkKind::LLVMLinkerOptions:
case AutolinkKind::SwiftAutoLinkExtract: {
// On platforms that support autolinking, continue to use the metadata.
for (LinkLibrary linkLib : AutolinkEntries) {
switch (linkLib.getKind()) {
case LibraryKind::Library: {
llvm::SmallString<32> opt =
getTargetDependentLibraryOption(IGM.Triple, linkLib.getName());
Entries.insert(llvm::MDNode::get(ctx, llvm::MDString::get(ctx, opt)));
continue;
}
case LibraryKind::Framework: {
llvm::Metadata *args[] = {llvm::MDString::get(ctx, "-framework"),
llvm::MDString::get(ctx, linkLib.getName())};
Entries.insert(llvm::MDNode::get(ctx, args));
continue;
}
}
llvm_unreachable("Unhandled LibraryKind in switch.");
}
return;
}
case AutolinkKind::LLVMDependentLibraries: {
for (LinkLibrary linkLib : AutolinkEntries) {
switch (linkLib.getKind()) {
case LibraryKind::Library: {
Entries.insert(llvm::MDNode::get(
ctx, llvm::MDString::get(ctx, linkLib.getName())));
continue;
}
case LibraryKind::Framework: {
llvm_unreachable(
"llvm.dependent-libraries doesn't support framework dependency");
}
}
llvm_unreachable("Unhandled LibraryKind in switch.");
}
return;
}
}
llvm_unreachable("Unhandled AutolinkKind in switch.");
}
template <typename Vector, typename Set>
void AutolinkKind::writeEntries(llvm::SetVector<llvm::MDNode *, Vector, Set> Entries,
llvm::NamedMDNode *Metadata, IRGenModule &IGM) {
switch (Value) {
case AutolinkKind::LLVMLinkerOptions:
case AutolinkKind::LLVMDependentLibraries: {
// On platforms that support autolinking, continue to use the metadata.
Metadata->clearOperands();
for (auto *Entry : AutolinkEntries)
for (auto *Entry : Entries)
Metadata->addOperand(Entry);
} else {
return;
}
case AutolinkKind::SwiftAutoLinkExtract: {
// Merge the entries into null-separated string.
llvm::SmallString<64> EntriesString;
for (auto &EntryNode : AutolinkEntries) {
const llvm::MDNode *MD = cast<llvm::MDNode>(EntryNode);
for (auto EntryNode : Entries) {
const auto *MD = cast<llvm::MDNode>(EntryNode);
for (auto &Entry : MD->operands()) {
const llvm::MDString *MS = cast<llvm::MDString>(Entry);
EntriesString += MS->getString();
@@ -1244,24 +1328,64 @@ void IRGenModule::emitAutolinkInfo() {
}
}
auto EntriesConstant = llvm::ConstantDataArray::getString(
getLLVMContext(), EntriesString, /*AddNull=*/false);
IGM.getLLVMContext(), EntriesString, /*AddNull=*/false);
// Mark the swift1_autolink_entries section with the SHF_EXCLUDE attribute
// to get the linker to drop it in the final linked binary.
// LLVM doesn't provide an interface to specify section attributs in the IR
// so we pass the attribute with inline assembly.
if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF)
Module.appendModuleInlineAsm(".section .swift1_autolink_entries,"
"\"0x80000000\"");
// LLVM doesn't provide an interface to specify section attributs in the
// IR so we pass the attribute with inline assembly.
if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::ELF)
IGM.Module.appendModuleInlineAsm(".section .swift1_autolink_entries,"
"\"0x80000000\"");
auto var =
new llvm::GlobalVariable(*getModule(), EntriesConstant->getType(), true,
llvm::GlobalValue::PrivateLinkage,
new llvm::GlobalVariable(*IGM.getModule(), EntriesConstant->getType(),
true, llvm::GlobalValue::PrivateLinkage,
EntriesConstant, "_swift1_autolink_entries");
var->setSection(".swift1_autolink_entries");
var->setAlignment(llvm::MaybeAlign(getPointerAlignment().getValue()));
var->setAlignment(llvm::MaybeAlign(IGM.getPointerAlignment().getValue()));
disableAddressSanitizer(*this, var);
addUsedGlobal(var);
disableAddressSanitizer(IGM, var);
IGM.addUsedGlobal(var);
return;
}
}
llvm_unreachable("Unhandled AutolinkKind in switch.");
}
AutolinkKind AutolinkKind::create(const SwiftTargetInfo &TargetInfo,
llvm::Triple Triple,
IRGenLLVMLTOKind LLVMLTOKind) {
// When performing LTO, we always use lld that supports auto linking
// mechanism with ELF. So embed dependent libraries names in
// "llvm.dependent-libraries" instead of "llvm.linker.options".
if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF &&
LLVMLTOKind != IRGenLLVMLTOKind::None) {
return AutolinkKind::LLVMDependentLibraries;
}
if (doesTargetAutolinkUsingAutolinkExtract(TargetInfo, Triple)) {
return AutolinkKind::SwiftAutoLinkExtract;
}
return AutolinkKind::LLVMLinkerOptions;
}
void IRGenModule::emitAutolinkInfo() {
auto Autolink =
AutolinkKind::create(TargetInfo, Triple, IRGen.Opts.LLVMLTOKind);
StringRef AutolinkSectionName = Autolink.getSectionNameMetadata();
auto *Metadata = Module.getOrInsertNamedMetadata(AutolinkSectionName);
llvm::SmallSetVector<llvm::MDNode *, 4> Entries;
// Collect the linker options already in the module (from ClangCodeGen).
for (auto Entry : Metadata->operands()) {
Entries.insert(Entry);
}
Autolink.collectEntriesFromLibraries(Entries, AutolinkEntries, *this);
Autolink.writeEntries(Entries, Metadata, *this);
if (!IRGen.Opts.ForceLoadSymbolName.empty() &&
(Triple.supportsCOMDAT() || isFirstObjectFileInModule(*this))) {