Skip to content

Commit d0131ba

Browse files
authored
Merge pull request #31146 from kateinoigakukun/katei/enable-lang-agnostic-lto
[LTO] Support LLVM level link time optimization on Darwin, Linux and Windows
2 parents b996a21 + 915c4a6 commit d0131ba

23 files changed

+256
-36
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 9 additions & 0 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,
@@ -217,6 +223,8 @@ class IRGenOptions {
217223
/// Whether we should embed the bitcode file.
218224
IRGenEmbedMode EmbedMode : 2;
219225

226+
IRGenLLVMLTOKind LLVMLTOKind: 2;
227+
220228
/// Add names to LLVM values.
221229
unsigned HasValueNamesSetting : 1;
222230
unsigned ValueNames : 1;
@@ -318,6 +326,7 @@ class IRGenOptions {
318326
DisableSwiftSpecificLLVMOptzns(false), DisableLLVMSLPVectorizer(false),
319327
Playground(false), EmitStackPromotionChecks(false),
320328
FunctionSections(false), PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
329+
LLVMLTOKind(IRGenLLVMLTOKind::None),
321330
HasValueNamesSetting(false), ValueNames(false),
322331
EnableReflectionMetadata(true), EnableReflectionNames(true),
323332
EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false),

include/swift/Driver/Action.h

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

332333
public:
333-
DynamicLinkJobAction(ArrayRef<const Action *> Inputs, LinkKind K)
334+
DynamicLinkJobAction(ArrayRef<const Action *> Inputs, LinkKind K, bool LTO)
334335
: JobAction(Action::Kind::DynamicLinkJob, Inputs, file_types::TY_Image),
335-
Kind(K) {
336+
Kind(K), LTO(LTO) {
336337
assert(Kind != LinkKind::None && Kind != LinkKind::StaticLibrary);
337338
}
338339

339340
LinkKind getKind() const { return Kind; }
340341

342+
bool PerformLTO() const { return LTO; }
343+
341344
static bool classof(const Action *A) {
342345
return A->getKind() == Action::Kind::DynamicLinkJob;
343346
}

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;

include/swift/Option/Options.td

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

502+
def lto : Joined<["-"], "lto=">,
503+
Flags<[FrontendOption, NoInteractiveOption]>,
504+
HelpText<"Specify the LTO type to either 'llvm' or 'llvm-full'">;
505+
502506
// Experimental feature options
503507

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

lib/Driver/DarwinToolChains.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,15 @@ toolchains::Darwin::addLinkerInputArgs(InvocationInfo &II,
238238
Arguments.push_back("-filelist");
239239
Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList"));
240240
II.FilelistInfos.push_back(
241-
{Arguments.back(), file_types::TY_Object,
241+
{Arguments.back(), context.OI.CompilerOutputType,
242242
FilelistInfo::WhichFiles::InputJobsAndSourceInputActions});
243243
} else {
244244
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
245245
file_types::TY_Object);
246+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
247+
file_types::TY_LLVM_BC);
246248
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
249+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
247250
}
248251

249252

@@ -306,6 +309,20 @@ toolchains::Darwin::addArgsToLinkARCLite(ArgStringList &Arguments,
306309
}
307310
}
308311

312+
void
313+
toolchains::Darwin::addLTOLibArgs(ArgStringList &Arguments,
314+
const JobContext &context) const {
315+
llvm::SmallString<128> LTOLibPath;
316+
if (findXcodeClangPath(LTOLibPath)) {
317+
llvm::sys::path::remove_filename(LTOLibPath); // 'clang'
318+
llvm::sys::path::remove_filename(LTOLibPath); // 'bin'
319+
llvm::sys::path::append(LTOLibPath, "lib", "libLTO.dylib");
320+
321+
Arguments.push_back("-lto_library");
322+
Arguments.push_back(context.Args.MakeArgString(LTOLibPath));
323+
}
324+
}
325+
309326
void
310327
toolchains::Darwin::addSanitizerArgs(ArgStringList &Arguments,
311328
const DynamicLinkJobAction &job,
@@ -723,6 +740,10 @@ toolchains::Darwin::constructInvocation(const DynamicLinkJobAction &job,
723740

724741
addArgsToLinkARCLite(Arguments, context);
725742

743+
if (job.PerformLTO()) {
744+
addLTOLibArgs(Arguments, context);
745+
}
746+
726747
for (const Arg *arg :
727748
context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) {
728749
Arguments.push_back("-F");
@@ -790,14 +811,17 @@ toolchains::Darwin::constructInvocation(const StaticLinkJobAction &job,
790811
if (context.shouldUseInputFileList()) {
791812
Arguments.push_back("-filelist");
792813
Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList"));
793-
II.FilelistInfos.push_back({Arguments.back(), file_types::TY_Object,
814+
II.FilelistInfos.push_back({Arguments.back(), context.OI.CompilerOutputType,
794815
FilelistInfo::WhichFiles::InputJobs});
795816
} else {
796817
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
797818
file_types::TY_Object);
819+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
820+
file_types::TY_LLVM_BC);
798821
}
799822

800823
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
824+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
801825

802826
Arguments.push_back("-o");
803827

lib/Driver/Driver.cpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,12 +1427,15 @@ static bool isSDKTooOld(StringRef sdkPath, const llvm::Triple &target) {
14271427
void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
14281428
const bool BatchMode, const InputFileList &Inputs,
14291429
OutputInfo &OI) const {
1430+
auto LinkerInputType = Args.hasArg(options::OPT_lto)
1431+
? file_types::TY_LLVM_BC
1432+
: file_types::TY_Object;
14301433
// By default, the driver does not link its output; this will be updated
14311434
// appropriately below if linking is required.
14321435

14331436
OI.CompilerOutputType = driverKind == DriverKind::Interactive
14341437
? file_types::TY_Nothing
1435-
: file_types::TY_Object;
1438+
: LinkerInputType;
14361439

14371440
if (const Arg *A = Args.getLastArg(options::OPT_num_threads)) {
14381441
if (BatchMode) {
@@ -1462,14 +1465,14 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
14621465
diag::error_static_emit_executable_disallowed);
14631466

14641467
OI.LinkAction = LinkKind::Executable;
1465-
OI.CompilerOutputType = file_types::TY_Object;
1468+
OI.CompilerOutputType = LinkerInputType;
14661469
break;
14671470

14681471
case options::OPT_emit_library:
14691472
OI.LinkAction = Args.hasArg(options::OPT_static) ?
14701473
LinkKind::StaticLibrary :
14711474
LinkKind::DynamicLibrary;
1472-
OI.CompilerOutputType = file_types::TY_Object;
1475+
OI.CompilerOutputType = LinkerInputType;
14731476
break;
14741477

14751478
case options::OPT_static:
@@ -1779,6 +1782,18 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
17791782

17801783
}
17811784

1785+
if (const Arg *A = Args.getLastArg(options::OPT_lto)) {
1786+
auto LTOVariant = llvm::StringSwitch<Optional<OutputInfo::LTOKind>>(A->getValue())
1787+
.Case("llvm", OutputInfo::LTOKind::LLVMThin)
1788+
.Case("llvm-full", OutputInfo::LTOKind::LLVMFull)
1789+
.Default(llvm::None);
1790+
if (LTOVariant)
1791+
OI.LTOVariant = LTOVariant.getValue();
1792+
else
1793+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
1794+
A->getAsString(Args), A->getValue());
1795+
}
1796+
17821797
if (TC.getTriple().isOSWindows()) {
17831798
if (const Arg *A = Args.getLastArg(options::OPT_libc)) {
17841799
OI.RuntimeVariant =
@@ -2113,15 +2128,17 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
21132128
MergeModuleAction = C.createAction<MergeModuleJobAction>(AllModuleInputs);
21142129
}
21152130

2131+
auto PerformLTO = Args.hasArg(options::OPT_lto);
21162132
if (OI.shouldLink() && !AllLinkerInputs.empty()) {
21172133
JobAction *LinkAction = nullptr;
21182134

21192135
if (OI.LinkAction == LinkKind::StaticLibrary) {
21202136
LinkAction = C.createAction<StaticLinkJobAction>(AllLinkerInputs,
2121-
OI.LinkAction);
2137+
OI.LinkAction);
21222138
} else {
21232139
LinkAction = C.createAction<DynamicLinkJobAction>(AllLinkerInputs,
2124-
OI.LinkAction);
2140+
OI.LinkAction,
2141+
PerformLTO);
21252142
}
21262143

21272144
// On ELF platforms there's no built in autolinking mechanism, so we
@@ -2130,7 +2147,7 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
21302147
const auto &Triple = TC.getTriple();
21312148
SmallVector<const Action *, 2> AutolinkExtractInputs;
21322149
for (const Action *A : AllLinkerInputs)
2133-
if (A->getType() == file_types::TY_Object) {
2150+
if (A->getType() == OI.CompilerOutputType) {
21342151
// Shared objects on ELF platforms don't have a swift1_autolink_entries
21352152
// section in them because the section in the .o files is marked as
21362153
// SHF_EXCLUDE.
@@ -2146,7 +2163,7 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
21462163
(Triple.getObjectFormat() == llvm::Triple::ELF && !Triple.isPS4()) ||
21472164
Triple.getObjectFormat() == llvm::Triple::Wasm ||
21482165
Triple.isOSCygMing();
2149-
if (!AutolinkExtractInputs.empty() && AutolinkExtractRequired) {
2166+
if (!AutolinkExtractInputs.empty() && AutolinkExtractRequired && !PerformLTO) {
21502167
auto *AutolinkExtractAction =
21512168
C.createAction<AutolinkExtractJobAction>(AutolinkExtractInputs);
21522169
// Takes the same inputs as the linker...

lib/Driver/ToolChains.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,11 @@ ToolChain::constructInvocation(const CompileJobAction &job,
518518
Arguments.push_back("-track-system-dependencies");
519519
}
520520

521+
if (auto arg = context.Args.getLastArg(options::OPT_lto)) {
522+
Arguments.push_back(context.Args.MakeArgString(
523+
Twine("-lto=") + arg->getValue()));
524+
}
525+
521526
context.Args.AddLastArg(
522527
Arguments,
523528
options::

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: 25 additions & 1 deletion
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(
@@ -167,6 +170,9 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
167170
std::string Linker;
168171
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
169172
Linker = A->getValue();
173+
} else if (context.OI.LTOVariant != OutputInfo::LTOKind::None) {
174+
// Force to use lld for LTO
175+
Linker = "lld";
170176
} else {
171177
Linker = getDefaultLinker();
172178
}
@@ -218,6 +224,16 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
218224
Arguments.push_back("-pie");
219225
}
220226

227+
switch (context.OI.LTOVariant) {
228+
case OutputInfo::LTOKind::LLVMThin:
229+
Arguments.push_back("-flto=thin");
230+
break;
231+
case OutputInfo::LTOKind::LLVMFull:
232+
Arguments.push_back("-flto=full");
233+
break;
234+
case OutputInfo::LTOKind::None: break;
235+
}
236+
221237
bool staticExecutable = false;
222238
bool staticStdlib = false;
223239

@@ -253,7 +269,11 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
253269

254270
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
255271
file_types::TY_Object);
272+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
273+
file_types::TY_LLVM_BC);
256274
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
275+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
276+
257277

258278
for (const Arg *arg :
259279
context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) {
@@ -368,15 +388,19 @@ toolchains::GenericUnix::constructInvocation(const StaticLinkJobAction &job,
368388
ArgStringList Arguments;
369389

370390
// Configure the toolchain.
371-
const char *AR = "ar";
391+
const char *AR = "llvm-ar";
372392
Arguments.push_back("crs");
373393

374394
Arguments.push_back(
375395
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
376396

377397
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
378398
file_types::TY_Object);
399+
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
400+
file_types::TY_LLVM_BC);
379401
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
402+
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
403+
380404

381405
InvocationInfo II{AR, Arguments};
382406

0 commit comments

Comments
 (0)