Skip to content

Commit 20bc0af

Browse files
[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
1 parent 3da8595 commit 20bc0af

File tree

14 files changed

+325
-64
lines changed

14 files changed

+325
-64
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ enum class IRGenDebugInfoFormat : unsigned {
6565
CodeView
6666
};
6767

68+
enum class IRGenLLVMLTOKind : unsigned {
69+
None,
70+
Thin,
71+
Full,
72+
};
73+
6874
enum class IRGenEmbedMode : unsigned {
6975
None,
7076
EmbedMarker,
@@ -220,6 +226,8 @@ class IRGenOptions {
220226
/// Whether we should embed the bitcode file.
221227
IRGenEmbedMode EmbedMode : 2;
222228

229+
IRGenLLVMLTOKind LLVMLTOKind : 2;
230+
223231
/// Add names to LLVM values.
224232
unsigned HasValueNamesSetting : 1;
225233
unsigned ValueNames : 1;
@@ -320,21 +328,21 @@ class IRGenOptions {
320328
DebugInfoLevel(IRGenDebugInfoLevel::None),
321329
DebugInfoFormat(IRGenDebugInfoFormat::None),
322330
DisableClangModuleSkeletonCUs(false), UseJIT(false),
323-
DisableLLVMOptzns(false),
324-
DisableSwiftSpecificLLVMOptzns(false), DisableLLVMSLPVectorizer(false),
325-
Playground(false), EmitStackPromotionChecks(false),
326-
FunctionSections(false), PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
327-
HasValueNamesSetting(false), ValueNames(false),
328-
EnableReflectionMetadata(true), EnableReflectionNames(true),
329-
EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false),
330-
LazyInitializeClassMetadata(false),
331+
DisableLLVMOptzns(false), DisableSwiftSpecificLLVMOptzns(false),
332+
DisableLLVMSLPVectorizer(false), Playground(false),
333+
EmitStackPromotionChecks(false), FunctionSections(false),
334+
PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
335+
LLVMLTOKind(IRGenLLVMLTOKind::None), HasValueNamesSetting(false),
336+
ValueNames(false), EnableReflectionMetadata(true),
337+
EnableReflectionNames(true), EnableAnonymousContextMangledNames(false),
338+
ForcePublicLinkage(false), LazyInitializeClassMetadata(false),
331339
LazyInitializeProtocolConformances(false), DisableLegacyTypeInfo(false),
332340
PrespecializeGenericMetadata(false), UseIncrementalLLVMCodeGen(true),
333-
UseSwiftCall(false), UseTypeLayoutValueHandling(true), GenerateProfile(false),
334-
EnableDynamicReplacementChaining(false),
341+
UseSwiftCall(false), UseTypeLayoutValueHandling(true),
342+
GenerateProfile(false), EnableDynamicReplacementChaining(false),
335343
DisableRoundTripDebugTypes(false), DisableDebuggerShadowCopies(false),
336-
DisableConcreteTypeMetadataMangledNameAccessors(false),
337-
CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()),
344+
DisableConcreteTypeMetadataMangledNameAccessors(false), CmdArgs(),
345+
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
338346
TypeInfoFilter(TypeInfoDumpFilter::All) {}
339347

340348
/// Appends to \p os an arbitrary string representing all options which

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,10 @@ def disable_bridging_pch : Flag<["-"], "disable-bridging-pch">,
523523
Flags<[HelpHidden]>,
524524
HelpText<"Disable automatic generation of bridging PCH files">;
525525

526+
def lto : Joined<["-"], "lto=">,
527+
Flags<[FrontendOption, NoInteractiveOption]>,
528+
HelpText<"Specify the LTO type to either 'llvm-thin' or 'llvm-full'">;
529+
526530
// Experimental feature options
527531

528532
// Note: this flag will be removed when JVP/differential generation in the

lib/Frontend/CompilerInvocation.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,18 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
14741474
}
14751475
}
14761476

1477+
if (const Arg *A = Args.getLastArg(options::OPT_lto)) {
1478+
auto LLVMLTOKind =
1479+
llvm::StringSwitch<Optional<IRGenLLVMLTOKind>>(A->getValue())
1480+
.Case("llvm-thin", IRGenLLVMLTOKind::Thin)
1481+
.Case("llvm-full", IRGenLLVMLTOKind::Full)
1482+
.Default(llvm::None);
1483+
if (LLVMLTOKind)
1484+
Opts.LLVMLTOKind = LLVMLTOKind.getValue();
1485+
else
1486+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
1487+
A->getAsString(Args), A->getValue());
1488+
}
14771489

14781490
if (const Arg *A = Args.getLastArg(options::OPT_sanitize_coverage_EQ)) {
14791491
Opts.SanitizeCoverage =

lib/IRGen/IRGen.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,9 +548,14 @@ bool swift::performLLVM(const IRGenOptions &Opts,
548548
case IRGenOutputKind::LLVMAssembly:
549549
EmitPasses.add(createPrintModulePass(*RawOS));
550550
break;
551-
case IRGenOutputKind::LLVMBitcode:
552-
EmitPasses.add(createBitcodeWriterPass(*RawOS));
551+
case IRGenOutputKind::LLVMBitcode: {
552+
if (Opts.LLVMLTOKind == IRGenLLVMLTOKind::Thin) {
553+
EmitPasses.add(createWriteThinLTOBitcodePass(*RawOS));
554+
} else {
555+
EmitPasses.add(createBitcodeWriterPass(*RawOS));
556+
}
553557
break;
558+
}
554559
case IRGenOutputKind::NativeAssembly:
555560
case IRGenOutputKind::ObjectFile: {
556561
CodeGenFileType FileType;

lib/IRGen/IRGenModule.cpp

Lines changed: 173 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,8 +1108,6 @@ llvm::SmallString<32> getTargetDependentLibraryOption(const llvm::Triple &T,
11081108
}
11091109

11101110
void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
1111-
llvm::LLVMContext &ctx = Module.getContext();
1112-
11131111
// The debugger gets the autolink information directly from
11141112
// the LinkLibraries of the module, so there's no reason to
11151113
// emit it into the IR of debugger expressions.
@@ -1118,10 +1116,7 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
11181116

11191117
switch (linkLib.getKind()) {
11201118
case LibraryKind::Library: {
1121-
llvm::SmallString<32> opt =
1122-
getTargetDependentLibraryOption(Triple, linkLib.getName());
1123-
AutolinkEntries.push_back(
1124-
llvm::MDNode::get(ctx, llvm::MDString::get(ctx, opt)));
1119+
AutolinkEntries.emplace_back(linkLib);
11251120
break;
11261121
}
11271122
case LibraryKind::Framework: {
@@ -1130,12 +1125,7 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
11301125
if (std::find(frameworks.begin(), frameworks.end(), linkLib.getName())
11311126
!= frameworks.end())
11321127
return;
1133-
1134-
llvm::Metadata *args[] = {
1135-
llvm::MDString::get(ctx, "-framework"),
1136-
llvm::MDString::get(ctx, linkLib.getName())
1137-
};
1138-
AutolinkEntries.push_back(llvm::MDNode::get(ctx, args));
1128+
AutolinkEntries.emplace_back(linkLib);
11391129
break;
11401130
}
11411131
}
@@ -1205,63 +1195,197 @@ static bool isFirstObjectFileInModule(IRGenModule &IGM) {
12051195
return containingModule->getFiles().front() == file;
12061196
}
12071197

1208-
void IRGenModule::emitAutolinkInfo() {
1209-
// Collect the linker options already in the module (from ClangCodeGen).
1198+
static bool
1199+
doesTargetAutolinkUsingAutolinkExtract(const SwiftTargetInfo &TargetInfo,
1200+
const llvm::Triple &Triple) {
1201+
if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF && !Triple.isPS4())
1202+
return true;
1203+
1204+
if (TargetInfo.OutputObjectFormat == llvm::Triple::Wasm)
1205+
return true;
1206+
1207+
if (Triple.isOSCygMing())
1208+
return true;
1209+
1210+
return false;
1211+
}
1212+
1213+
namespace {
1214+
1215+
struct AutolinkKind {
1216+
enum ValueTy {
1217+
LLVMLinkerOptions,
1218+
LLVMDependentLibraries,
1219+
SwiftAutoLinkExtract,
1220+
};
1221+
1222+
ValueTy Value;
1223+
1224+
AutolinkKind(ValueTy value) : Value(value) {}
1225+
AutolinkKind(const AutolinkKind &kind) : Value(kind.Value) {}
1226+
1227+
StringRef getSectionNameMetadata();
1228+
1229+
template <typename Vector, typename Set>
1230+
void collectEntriesFromLibraries(llvm::SetVector<llvm::MDNode *, Vector, Set> &Entries,
1231+
ArrayRef<LinkLibrary> AutolinkEntries,
1232+
IRGenModule &IGM);
1233+
1234+
template <typename Vector, typename Set>
1235+
void writeEntries(llvm::SetVector<llvm::MDNode *, Vector, Set> Entries,
1236+
llvm::NamedMDNode *Metadata, IRGenModule &IGM);
1237+
1238+
static AutolinkKind create(const SwiftTargetInfo &TargetInfo,
1239+
llvm::Triple Triple, IRGenLLVMLTOKind LLVMLTOKind);
1240+
};
1241+
1242+
} // anonymous namespace
1243+
1244+
StringRef AutolinkKind::getSectionNameMetadata() {
12101245
// FIXME: This constant should be vended by LLVM somewhere.
1211-
auto *Metadata = Module.getOrInsertNamedMetadata("llvm.linker.options");
1212-
for (llvm::MDNode *LinkOption : Metadata->operands())
1213-
AutolinkEntries.push_back(LinkOption);
1214-
1215-
// Remove duplicates.
1216-
llvm::SmallPtrSet<llvm::MDNode *, 4> knownAutolinkEntries;
1217-
AutolinkEntries.erase(std::remove_if(AutolinkEntries.begin(),
1218-
AutolinkEntries.end(),
1219-
[&](llvm::MDNode *entry) -> bool {
1220-
return !knownAutolinkEntries.insert(
1221-
entry).second;
1222-
}),
1223-
AutolinkEntries.end());
1224-
1225-
const bool AutolinkExtractRequired =
1226-
(TargetInfo.OutputObjectFormat == llvm::Triple::ELF && !Triple.isPS4()) ||
1227-
TargetInfo.OutputObjectFormat == llvm::Triple::Wasm ||
1228-
Triple.isOSCygMing();
1229-
1230-
if (!AutolinkExtractRequired) {
1246+
switch (Value) {
1247+
case AutolinkKind::LLVMDependentLibraries:
1248+
return "llvm.dependent-libraries";
1249+
case AutolinkKind::LLVMLinkerOptions:
1250+
case AutolinkKind::SwiftAutoLinkExtract:
1251+
return "llvm.linker.options";
1252+
}
1253+
1254+
llvm_unreachable("Unhandled AutolinkKind in switch.");
1255+
}
1256+
1257+
template <typename Vector, typename Set>
1258+
void AutolinkKind::collectEntriesFromLibraries(
1259+
llvm::SetVector<llvm::MDNode *, Vector, Set> &Entries,
1260+
ArrayRef<LinkLibrary> AutolinkEntries, IRGenModule &IGM) {
1261+
llvm::LLVMContext &ctx = IGM.getLLVMContext();
1262+
1263+
switch (Value) {
1264+
case AutolinkKind::LLVMLinkerOptions:
1265+
case AutolinkKind::SwiftAutoLinkExtract: {
1266+
// On platforms that support autolinking, continue to use the metadata.
1267+
for (LinkLibrary linkLib : AutolinkEntries) {
1268+
switch (linkLib.getKind()) {
1269+
case LibraryKind::Library: {
1270+
llvm::SmallString<32> opt =
1271+
getTargetDependentLibraryOption(IGM.Triple, linkLib.getName());
1272+
Entries.insert(llvm::MDNode::get(ctx, llvm::MDString::get(ctx, opt)));
1273+
continue;
1274+
}
1275+
case LibraryKind::Framework: {
1276+
llvm::Metadata *args[] = {llvm::MDString::get(ctx, "-framework"),
1277+
llvm::MDString::get(ctx, linkLib.getName())};
1278+
Entries.insert(llvm::MDNode::get(ctx, args));
1279+
continue;
1280+
}
1281+
}
1282+
llvm_unreachable("Unhandled LibraryKind in switch.");
1283+
}
1284+
return;
1285+
}
1286+
case AutolinkKind::LLVMDependentLibraries: {
1287+
for (LinkLibrary linkLib : AutolinkEntries) {
1288+
switch (linkLib.getKind()) {
1289+
case LibraryKind::Library: {
1290+
Entries.insert(llvm::MDNode::get(
1291+
ctx, llvm::MDString::get(ctx, linkLib.getName())));
1292+
continue;
1293+
}
1294+
case LibraryKind::Framework: {
1295+
llvm_unreachable(
1296+
"llvm.dependent-libraries doesn't support framework dependency");
1297+
}
1298+
}
1299+
llvm_unreachable("Unhandled LibraryKind in switch.");
1300+
}
1301+
return;
1302+
}
1303+
}
1304+
llvm_unreachable("Unhandled AutolinkKind in switch.");
1305+
}
1306+
1307+
template <typename Vector, typename Set>
1308+
void AutolinkKind::writeEntries(llvm::SetVector<llvm::MDNode *, Vector, Set> Entries,
1309+
llvm::NamedMDNode *Metadata, IRGenModule &IGM) {
1310+
switch (Value) {
1311+
case AutolinkKind::LLVMLinkerOptions:
1312+
case AutolinkKind::LLVMDependentLibraries: {
12311313
// On platforms that support autolinking, continue to use the metadata.
12321314
Metadata->clearOperands();
1233-
for (auto *Entry : AutolinkEntries)
1315+
for (auto *Entry : Entries)
12341316
Metadata->addOperand(Entry);
1235-
} else {
1317+
return;
1318+
}
1319+
case AutolinkKind::SwiftAutoLinkExtract: {
12361320
// Merge the entries into null-separated string.
12371321
llvm::SmallString<64> EntriesString;
1238-
for (auto &EntryNode : AutolinkEntries) {
1239-
const llvm::MDNode *MD = cast<llvm::MDNode>(EntryNode);
1322+
for (auto EntryNode : Entries) {
1323+
const auto *MD = cast<llvm::MDNode>(EntryNode);
12401324
for (auto &Entry : MD->operands()) {
12411325
const llvm::MDString *MS = cast<llvm::MDString>(Entry);
12421326
EntriesString += MS->getString();
12431327
EntriesString += '\0';
12441328
}
12451329
}
12461330
auto EntriesConstant = llvm::ConstantDataArray::getString(
1247-
getLLVMContext(), EntriesString, /*AddNull=*/false);
1331+
IGM.getLLVMContext(), EntriesString, /*AddNull=*/false);
12481332
// Mark the swift1_autolink_entries section with the SHF_EXCLUDE attribute
12491333
// to get the linker to drop it in the final linked binary.
1250-
// LLVM doesn't provide an interface to specify section attributs in the IR
1251-
// so we pass the attribute with inline assembly.
1252-
if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF)
1253-
Module.appendModuleInlineAsm(".section .swift1_autolink_entries,"
1254-
"\"0x80000000\"");
1334+
// LLVM doesn't provide an interface to specify section attributs in the
1335+
// IR so we pass the attribute with inline assembly.
1336+
if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::ELF)
1337+
IGM.Module.appendModuleInlineAsm(".section .swift1_autolink_entries,"
1338+
"\"0x80000000\"");
12551339
auto var =
1256-
new llvm::GlobalVariable(*getModule(), EntriesConstant->getType(), true,
1257-
llvm::GlobalValue::PrivateLinkage,
1340+
new llvm::GlobalVariable(*IGM.getModule(), EntriesConstant->getType(),
1341+
true, llvm::GlobalValue::PrivateLinkage,
12581342
EntriesConstant, "_swift1_autolink_entries");
12591343
var->setSection(".swift1_autolink_entries");
1260-
var->setAlignment(llvm::MaybeAlign(getPointerAlignment().getValue()));
1344+
var->setAlignment(llvm::MaybeAlign(IGM.getPointerAlignment().getValue()));
12611345

1262-
disableAddressSanitizer(*this, var);
1263-
addUsedGlobal(var);
1346+
disableAddressSanitizer(IGM, var);
1347+
IGM.addUsedGlobal(var);
1348+
return;
12641349
}
1350+
}
1351+
llvm_unreachable("Unhandled AutolinkKind in switch.");
1352+
}
1353+
1354+
AutolinkKind AutolinkKind::create(const SwiftTargetInfo &TargetInfo,
1355+
llvm::Triple Triple,
1356+
IRGenLLVMLTOKind LLVMLTOKind) {
1357+
// When performing LTO, we always use lld that supports auto linking
1358+
// mechanism with ELF. So embed dependent libraries names in
1359+
// "llvm.dependent-libraries" instead of "llvm.linker.options".
1360+
if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF &&
1361+
LLVMLTOKind != IRGenLLVMLTOKind::None) {
1362+
return AutolinkKind::LLVMDependentLibraries;
1363+
}
1364+
1365+
if (doesTargetAutolinkUsingAutolinkExtract(TargetInfo, Triple)) {
1366+
return AutolinkKind::SwiftAutoLinkExtract;
1367+
}
1368+
1369+
return AutolinkKind::LLVMLinkerOptions;
1370+
}
1371+
1372+
void IRGenModule::emitAutolinkInfo() {
1373+
auto Autolink =
1374+
AutolinkKind::create(TargetInfo, Triple, IRGen.Opts.LLVMLTOKind);
1375+
1376+
StringRef AutolinkSectionName = Autolink.getSectionNameMetadata();
1377+
1378+
auto *Metadata = Module.getOrInsertNamedMetadata(AutolinkSectionName);
1379+
llvm::SmallSetVector<llvm::MDNode *, 4> Entries;
1380+
1381+
// Collect the linker options already in the module (from ClangCodeGen).
1382+
for (auto Entry : Metadata->operands()) {
1383+
Entries.insert(Entry);
1384+
}
1385+
1386+
Autolink.collectEntriesFromLibraries(Entries, AutolinkEntries, *this);
1387+
1388+
Autolink.writeEntries(Entries, Metadata, *this);
12651389

12661390
if (!IRGen.Opts.ForceLoadSymbolName.empty() &&
12671391
(Triple.supportsCOMDAT() || isFirstObjectFileInModule(*this))) {

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "SwiftTargetInfo.h"
2323
#include "TypeLayout.h"
2424
#include "swift/AST/Decl.h"
25+
#include "swift/AST/LinkLibrary.h"
2526
#include "swift/AST/Module.h"
2627
#include "swift/AST/ReferenceCounting.h"
2728
#include "swift/AST/SourceFile.h"
@@ -1076,7 +1077,7 @@ class IRGenModule {
10761077
SmallVector<llvm::WeakTrackingVH, 4> LLVMCompilerUsed;
10771078

10781079
/// Metadata nodes for autolinking info.
1079-
SmallVector<llvm::MDNode *, 32> AutolinkEntries;
1080+
SmallVector<LinkLibrary, 32> AutolinkEntries;
10801081

10811082
/// List of Objective-C classes, bitcast to i8*.
10821083
SmallVector<llvm::WeakTrackingVH, 4> ObjCClasses;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
extern int IComeFromLinkFramework;

test/IRGen/Inputs/Frameworks/LinkFramework.framework/LinkFramework

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
framework module LinkFramework {
2+
header "LinkFramework.h"
3+
export *
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#pragma comment(lib, "transitive-module")

0 commit comments

Comments
 (0)