Skip to content

Commit d6cddaa

Browse files
[LTO] Support LLVM LTO for driver
This commit adds LTO support for handling linker options and LLVM BC emission. Even for ELF, swift-autolink-extract is unnecessary because linker options are embeded in LLVM BC content when LTO.
1 parent 063d420 commit d6cddaa

File tree

14 files changed

+299
-21
lines changed

14 files changed

+299
-21
lines changed

include/swift/Driver/Action.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,16 +328,20 @@ class GeneratePCHJobAction : public JobAction {
328328
class DynamicLinkJobAction : public JobAction {
329329
virtual void anchor();
330330
LinkKind Kind;
331+
bool ShouldPerformLTO;
331332

332333
public:
333-
DynamicLinkJobAction(ArrayRef<const Action *> Inputs, LinkKind K)
334+
DynamicLinkJobAction(ArrayRef<const Action *> Inputs, LinkKind K,
335+
bool ShouldPerformLTO)
334336
: JobAction(Action::Kind::DynamicLinkJob, Inputs, file_types::TY_Image),
335-
Kind(K) {
337+
Kind(K), ShouldPerformLTO(ShouldPerformLTO) {
336338
assert(Kind != LinkKind::None && Kind != LinkKind::StaticLibrary);
337339
}
338340

339341
LinkKind getKind() const { return Kind; }
340342

343+
bool shouldPerformLTO() const { return ShouldPerformLTO; }
344+
341345
static bool classof(const Action *A) {
342346
return A->getKind() == Action::Kind::DynamicLinkJob;
343347
}

include/swift/Driver/Driver.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ class OutputInfo {
101101
/// The output type which should be used for compile actions.
102102
file_types::ID CompilerOutputType = file_types::ID::TY_INVALID;
103103

104+
enum class LTOKind {
105+
None,
106+
LLVMThin,
107+
LLVMFull,
108+
};
109+
110+
LTOKind LTOVariant = LTOKind::None;
111+
104112
/// Describes if and how the output of compile actions should be
105113
/// linked together.
106114
LinkKind LinkAction = LinkKind::None;

lib/Driver/DarwinToolChains.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,19 @@ static bool findXcodeClangPath(llvm::SmallVectorImpl<char> &path) {
202202
return !path.empty();
203203
}
204204

205+
static bool findXcodeClangLibPath(const Twine &libName,
206+
llvm::SmallVectorImpl<char> &path) {
207+
assert(path.empty());
208+
209+
if (!findXcodeClangPath(path)) {
210+
return false;
211+
}
212+
llvm::sys::path::remove_filename(path); // 'clang'
213+
llvm::sys::path::remove_filename(path); // 'bin'
214+
llvm::sys::path::append(path, "lib", libName);
215+
return true;
216+
}
217+
205218
static void addVersionString(const ArgList &inputArgs, ArgStringList &arguments,
206219
unsigned major, unsigned minor, unsigned micro) {
207220
llvm::SmallString<8> buf;
@@ -239,12 +252,15 @@ toolchains::Darwin::addLinkerInputArgs(InvocationInfo &II,
239252
Arguments.push_back("-filelist");
240253
Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList"));
241254
II.FilelistInfos.push_back(
242-
{Arguments.back(), file_types::TY_Object,
255+
{Arguments.back(), context.OI.CompilerOutputType,
243256
FilelistInfo::WhichFiles::InputJobsAndSourceInputActions});
244257
} else {
245258
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
246259
file_types::TY_Object);
260+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
261+
file_types::TY_LLVM_BC);
247262
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
263+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
248264
}
249265

250266

@@ -274,11 +290,7 @@ static void findARCLiteLibPath(const toolchains::Darwin &TC,
274290
// If we don't have a 'lib/arc/' directory, find the "arclite" library
275291
// relative to the Clang in the active Xcode.
276292
ARCLiteLib.clear();
277-
if (findXcodeClangPath(ARCLiteLib)) {
278-
llvm::sys::path::remove_filename(ARCLiteLib); // 'clang'
279-
llvm::sys::path::remove_filename(ARCLiteLib); // 'bin'
280-
llvm::sys::path::append(ARCLiteLib, "lib", "arc");
281-
}
293+
findXcodeClangLibPath("arc", ARCLiteLib);
282294
}
283295
}
284296

@@ -307,6 +319,15 @@ toolchains::Darwin::addArgsToLinkARCLite(ArgStringList &Arguments,
307319
}
308320
}
309321

322+
void toolchains::Darwin::addLTOLibArgs(ArgStringList &Arguments,
323+
const JobContext &context) const {
324+
llvm::SmallString<128> LTOLibPath;
325+
if (findXcodeClangLibPath("libLTO.dylib", LTOLibPath)) {
326+
Arguments.push_back("-lto_library");
327+
Arguments.push_back(context.Args.MakeArgString(LTOLibPath));
328+
}
329+
}
330+
310331
void
311332
toolchains::Darwin::addSanitizerArgs(ArgStringList &Arguments,
312333
const DynamicLinkJobAction &job,
@@ -761,6 +782,10 @@ toolchains::Darwin::constructInvocation(const DynamicLinkJobAction &job,
761782

762783
addArgsToLinkARCLite(Arguments, context);
763784

785+
if (job.shouldPerformLTO()) {
786+
addLTOLibArgs(Arguments, context);
787+
}
788+
764789
for (const Arg *arg :
765790
context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) {
766791
Arguments.push_back("-F");
@@ -828,14 +853,17 @@ toolchains::Darwin::constructInvocation(const StaticLinkJobAction &job,
828853
if (context.shouldUseInputFileList()) {
829854
Arguments.push_back("-filelist");
830855
Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList"));
831-
II.FilelistInfos.push_back({Arguments.back(), file_types::TY_Object,
856+
II.FilelistInfos.push_back({Arguments.back(), context.OI.CompilerOutputType,
832857
FilelistInfo::WhichFiles::InputJobs});
833858
} else {
834859
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
835860
file_types::TY_Object);
861+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
862+
file_types::TY_LLVM_BC);
836863
}
837864

838865
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
866+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
839867

840868
Arguments.push_back("-o");
841869

lib/Driver/Driver.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,12 +1433,29 @@ static bool isSDKTooOld(StringRef sdkPath, const llvm::Triple &target) {
14331433
void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
14341434
const bool BatchMode, const InputFileList &Inputs,
14351435
OutputInfo &OI) const {
1436+
1437+
if (const Arg *A = Args.getLastArg(options::OPT_lto)) {
1438+
auto LTOVariant =
1439+
llvm::StringSwitch<Optional<OutputInfo::LTOKind>>(A->getValue())
1440+
.Case("llvm-thin", OutputInfo::LTOKind::LLVMThin)
1441+
.Case("llvm-full", OutputInfo::LTOKind::LLVMFull)
1442+
.Default(llvm::None);
1443+
if (LTOVariant)
1444+
OI.LTOVariant = LTOVariant.getValue();
1445+
else
1446+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
1447+
A->getAsString(Args), A->getValue());
1448+
}
1449+
1450+
auto CompilerOutputType = OI.LTOVariant != OutputInfo::LTOKind::None
1451+
? file_types::TY_LLVM_BC
1452+
: file_types::TY_Object;
14361453
// By default, the driver does not link its output; this will be updated
14371454
// appropriately below if linking is required.
14381455

14391456
OI.CompilerOutputType = driverKind == DriverKind::Interactive
14401457
? file_types::TY_Nothing
1441-
: file_types::TY_Object;
1458+
: CompilerOutputType;
14421459

14431460
if (const Arg *A = Args.getLastArg(options::OPT_num_threads)) {
14441461
if (BatchMode) {
@@ -1468,14 +1485,14 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
14681485
diag::error_static_emit_executable_disallowed);
14691486

14701487
OI.LinkAction = LinkKind::Executable;
1471-
OI.CompilerOutputType = file_types::TY_Object;
1488+
OI.CompilerOutputType = CompilerOutputType;
14721489
break;
14731490

14741491
case options::OPT_emit_library:
14751492
OI.LinkAction = Args.hasArg(options::OPT_static) ?
14761493
LinkKind::StaticLibrary :
14771494
LinkKind::DynamicLibrary;
1478-
OI.CompilerOutputType = file_types::TY_Object;
1495+
OI.CompilerOutputType = CompilerOutputType;
14791496
break;
14801497

14811498
case options::OPT_static:
@@ -2119,15 +2136,16 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
21192136
MergeModuleAction = C.createAction<MergeModuleJobAction>(AllModuleInputs);
21202137
}
21212138

2139+
bool shouldPerformLTO = OI.LTOVariant != OutputInfo::LTOKind::None;
21222140
if (OI.shouldLink() && !AllLinkerInputs.empty()) {
21232141
JobAction *LinkAction = nullptr;
21242142

21252143
if (OI.LinkAction == LinkKind::StaticLibrary) {
2126-
LinkAction = C.createAction<StaticLinkJobAction>(AllLinkerInputs,
2127-
OI.LinkAction);
2144+
LinkAction =
2145+
C.createAction<StaticLinkJobAction>(AllLinkerInputs, OI.LinkAction);
21282146
} else {
2129-
LinkAction = C.createAction<DynamicLinkJobAction>(AllLinkerInputs,
2130-
OI.LinkAction);
2147+
LinkAction = C.createAction<DynamicLinkJobAction>(
2148+
AllLinkerInputs, OI.LinkAction, shouldPerformLTO);
21312149
}
21322150

21332151
// On ELF platforms there's no built in autolinking mechanism, so we
@@ -2149,9 +2167,10 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
21492167
AutolinkExtractInputs.push_back(A);
21502168
}
21512169
const bool AutolinkExtractRequired =
2152-
(Triple.getObjectFormat() == llvm::Triple::ELF && !Triple.isPS4()) ||
2153-
Triple.getObjectFormat() == llvm::Triple::Wasm ||
2154-
Triple.isOSCygMing();
2170+
((Triple.getObjectFormat() == llvm::Triple::ELF && !Triple.isPS4()) ||
2171+
Triple.getObjectFormat() == llvm::Triple::Wasm ||
2172+
Triple.isOSCygMing()) &&
2173+
!shouldPerformLTO;
21552174
if (!AutolinkExtractInputs.empty() && AutolinkExtractRequired) {
21562175
auto *AutolinkExtractAction =
21572176
C.createAction<AutolinkExtractJobAction>(AutolinkExtractInputs);

lib/Driver/ToolChains.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,19 @@ static bool addOutputsOfType(ArgStringList &Arguments,
128128
return Added;
129129
}
130130

131+
static void addLTOArgs(const OutputInfo &OI, ArgStringList &arguments) {
132+
switch (OI.LTOVariant) {
133+
case OutputInfo::LTOKind::None:
134+
break;
135+
case OutputInfo::LTOKind::LLVMThin:
136+
arguments.push_back("-lto=llvm-thin");
137+
break;
138+
case OutputInfo::LTOKind::LLVMFull:
139+
arguments.push_back("-lto=llvm-full");
140+
break;
141+
}
142+
}
143+
131144
void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
132145
const CommandOutput &output,
133146
const ArgList &inputArgs,
@@ -284,6 +297,8 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
284297
arguments.push_back(inputArgs.MakeArgString(workingDirectory));
285298
}
286299

300+
addLTOArgs(OI, arguments);
301+
287302
// -g implies -enable-anonymous-context-mangled-names, because the extra
288303
// metadata aids debugging.
289304
if (inputArgs.hasArg(options::OPT_g)) {

lib/Driver/ToolChains.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain {
4848
void addDeploymentTargetArgs(llvm::opt::ArgStringList &Arguments,
4949
const JobContext &context) const;
5050

51+
void addLTOLibArgs(llvm::opt::ArgStringList &Arguments,
52+
const JobContext &context) const;
53+
5154
void addCommonFrontendArgs(
5255
const OutputInfo &OI, const CommandOutput &output,
5356
const llvm::opt::ArgList &inputArgs,

lib/Driver/UnixToolChains.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation(
7272

7373
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
7474
file_types::TY_Object);
75+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
76+
file_types::TY_LLVM_BC);
7577
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
78+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
7679

7780
Arguments.push_back("-o");
7881
Arguments.push_back(
@@ -165,9 +168,18 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
165168

166169
// Select the linker to use.
167170
std::string Linker;
171+
if (context.OI.LTOVariant != OutputInfo::LTOKind::None) {
172+
// Force to use lld for LTO on Unix-like platform (not including Darwin)
173+
// because we don't support gold LTO or something else except for lld LTO
174+
// at this time.
175+
Linker = "lld";
176+
}
177+
168178
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
169179
Linker = A->getValue();
170-
} else {
180+
}
181+
182+
if (Linker.empty()) {
171183
Linker = getDefaultLinker();
172184
}
173185
if (!Linker.empty()) {
@@ -218,6 +230,17 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
218230
Arguments.push_back("-pie");
219231
}
220232

233+
switch (context.OI.LTOVariant) {
234+
case OutputInfo::LTOKind::LLVMThin:
235+
Arguments.push_back("-flto=thin");
236+
break;
237+
case OutputInfo::LTOKind::LLVMFull:
238+
Arguments.push_back("-flto=full");
239+
break;
240+
case OutputInfo::LTOKind::None:
241+
break;
242+
}
243+
221244
bool staticExecutable = false;
222245
bool staticStdlib = false;
223246

@@ -253,7 +276,10 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
253276

254277
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
255278
file_types::TY_Object);
279+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
280+
file_types::TY_LLVM_BC);
256281
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
282+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
257283

258284
for (const Arg *arg :
259285
context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) {
@@ -368,15 +394,19 @@ toolchains::GenericUnix::constructInvocation(const StaticLinkJobAction &job,
368394
ArgStringList Arguments;
369395

370396
// Configure the toolchain.
371-
const char *AR = "ar";
397+
const char *AR =
398+
context.OI.LTOVariant != OutputInfo::LTOKind::None ? "llvm-ar" : "ar";
372399
Arguments.push_back("crs");
373400

374401
Arguments.push_back(
375402
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
376403

377404
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
378405
file_types::TY_Object);
406+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
407+
file_types::TY_LLVM_BC);
379408
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
409+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
380410

381411
InvocationInfo II{AR, Arguments};
382412

lib/Driver/WindowsToolChains.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
7676
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
7777
Linker = A->getValue();
7878
}
79+
80+
switch (context.OI.LTOVariant) {
81+
case OutputInfo::LTOKind::LLVMThin:
82+
Arguments.push_back("-flto=thin");
83+
break;
84+
case OutputInfo::LTOKind::LLVMFull:
85+
Arguments.push_back("-flto=full");
86+
break;
87+
case OutputInfo::LTOKind::None:
88+
break;
89+
}
90+
91+
if (Linker.empty() && context.OI.LTOVariant != OutputInfo::LTOKind::None) {
92+
// Force to use lld for LTO on Windows because we don't support link LTO or
93+
// something else except for lld LTO at this time.
94+
Linker = "lld";
95+
}
96+
7997
if (!Linker.empty())
8098
Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker));
8199

@@ -143,7 +161,10 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
143161

144162
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
145163
file_types::TY_Object);
164+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
165+
file_types::TY_LLVM_BC);
146166
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
167+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
147168

148169
for (const Arg *arg :
149170
context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) {

0 commit comments

Comments
 (0)