mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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:
@@ -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))) {
|
||||
|
||||
Reference in New Issue
Block a user