Skip to content

[LTO] Support LLVM level link time optimization on Darwin, Linux and Windows #31146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ enum class IRGenDebugInfoFormat : unsigned {
CodeView
};

enum class IRGenLLVMLTOKind : unsigned {
None,
Thin,
Full
};

enum class IRGenEmbedMode : unsigned {
None,
EmbedMarker,
Expand Down Expand Up @@ -221,6 +227,8 @@ class IRGenOptions {
/// Whether we should embed the bitcode file.
IRGenEmbedMode EmbedMode : 2;

IRGenLLVMLTOKind LLVMLTOKind: 2;

/// Add names to LLVM values.
unsigned HasValueNamesSetting : 1;
unsigned ValueNames : 1;
Expand Down Expand Up @@ -323,6 +331,7 @@ class IRGenOptions {
DisableFPElimLeaf(false),
DisableFPElim(true), Playground(false), EmitStackPromotionChecks(false),
FunctionSections(false), PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
LLVMLTOKind(IRGenLLVMLTOKind::None),
HasValueNamesSetting(false), ValueNames(false),
EnableReflectionMetadata(true), EnableReflectionNames(true),
EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false),
Expand Down
7 changes: 5 additions & 2 deletions include/swift/Driver/Action.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,16 +329,19 @@ class GeneratePCHJobAction : public JobAction {
class DynamicLinkJobAction : public JobAction {
virtual void anchor();
LinkKind Kind;
bool LTO;

public:
DynamicLinkJobAction(ArrayRef<const Action *> Inputs, LinkKind K)
DynamicLinkJobAction(ArrayRef<const Action *> Inputs, LinkKind K, bool LTO)
: JobAction(Action::Kind::DynamicLinkJob, Inputs, file_types::TY_Image),
Kind(K) {
Kind(K), LTO(LTO) {
assert(Kind != LinkKind::None && Kind != LinkKind::StaticLibrary);
}

LinkKind getKind() const { return Kind; }

bool PerformLTO() const { return LTO; }

static bool classof(const Action *A) {
return A->getKind() == Action::Kind::DynamicLinkJob;
}
Expand Down
8 changes: 8 additions & 0 deletions include/swift/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ class OutputInfo {
/// The output type which should be used for compile actions.
file_types::ID CompilerOutputType = file_types::ID::TY_INVALID;

enum class LTOKind {
None,
LLVMThin,
LLVMFull,
};

LTOKind LTOVariant = LTOKind::None;

/// Describes if and how the output of compile actions should be
/// linked together.
LinkKind LinkAction = LinkKind::None;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,10 @@ def disable_bridging_pch : Flag<["-"], "disable-bridging-pch">,
Flags<[HelpHidden]>,
HelpText<"Disable automatic generation of bridging PCH files">;

def lto : Joined<["-"], "lto=">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Specify the LTO type to either 'llvm' or 'llvm-full'">;

// Experimental feature options

// Note: this flag will be removed when JVP/differential generation in the
Expand Down
28 changes: 26 additions & 2 deletions lib/Driver/DarwinToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,12 +238,15 @@ toolchains::Darwin::addLinkerInputArgs(InvocationInfo &II,
Arguments.push_back("-filelist");
Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList"));
II.FilelistInfos.push_back(
{Arguments.back(), file_types::TY_Object,
{Arguments.back(), context.OI.CompilerOutputType,
FilelistInfo::WhichFiles::InputJobsAndSourceInputActions});
} else {
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_Object);
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_LLVM_BC);
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);
}


Expand Down Expand Up @@ -306,6 +309,20 @@ toolchains::Darwin::addArgsToLinkARCLite(ArgStringList &Arguments,
}
}

void
toolchains::Darwin::addLTOLibArgs(ArgStringList &Arguments,
const JobContext &context) const {
llvm::SmallString<128> LTOLibPath;
if (findXcodeClangPath(LTOLibPath)) {
llvm::sys::path::remove_filename(LTOLibPath); // 'clang'
llvm::sys::path::remove_filename(LTOLibPath); // 'bin'
llvm::sys::path::append(LTOLibPath, "lib", "libLTO.dylib");

Arguments.push_back("-lto_library");
Arguments.push_back(context.Args.MakeArgString(LTOLibPath));
}
}

void
toolchains::Darwin::addSanitizerArgs(ArgStringList &Arguments,
const DynamicLinkJobAction &job,
Expand Down Expand Up @@ -723,6 +740,10 @@ toolchains::Darwin::constructInvocation(const DynamicLinkJobAction &job,

addArgsToLinkARCLite(Arguments, context);

if (job.PerformLTO()) {
addLTOLibArgs(Arguments, context);
}

for (const Arg *arg :
context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) {
Arguments.push_back("-F");
Expand Down Expand Up @@ -790,14 +811,17 @@ toolchains::Darwin::constructInvocation(const StaticLinkJobAction &job,
if (context.shouldUseInputFileList()) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList"));
II.FilelistInfos.push_back({Arguments.back(), file_types::TY_Object,
II.FilelistInfos.push_back({Arguments.back(), context.OI.CompilerOutputType,
FilelistInfo::WhichFiles::InputJobs});
} else {
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_Object);
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_LLVM_BC);
}

addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);

Arguments.push_back("-o");

Expand Down
31 changes: 24 additions & 7 deletions lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1427,12 +1427,15 @@ static bool isSDKTooOld(StringRef sdkPath, const llvm::Triple &target) {
void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
const bool BatchMode, const InputFileList &Inputs,
OutputInfo &OI) const {
auto LinkerInputType = Args.hasArg(options::OPT_lto)
? file_types::TY_LLVM_BC
: file_types::TY_Object;
// By default, the driver does not link its output; this will be updated
// appropriately below if linking is required.

OI.CompilerOutputType = driverKind == DriverKind::Interactive
? file_types::TY_Nothing
: file_types::TY_Object;
: LinkerInputType;

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

OI.LinkAction = LinkKind::Executable;
OI.CompilerOutputType = file_types::TY_Object;
OI.CompilerOutputType = LinkerInputType;
break;

case options::OPT_emit_library:
OI.LinkAction = Args.hasArg(options::OPT_static) ?
LinkKind::StaticLibrary :
LinkKind::DynamicLibrary;
OI.CompilerOutputType = file_types::TY_Object;
OI.CompilerOutputType = LinkerInputType;
break;

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

}

if (const Arg *A = Args.getLastArg(options::OPT_lto)) {
auto LTOVariant = llvm::StringSwitch<Optional<OutputInfo::LTOKind>>(A->getValue())
.Case("llvm", OutputInfo::LTOKind::LLVMThin)
.Case("llvm-full", OutputInfo::LTOKind::LLVMFull)
.Default(llvm::None);
if (LTOVariant)
OI.LTOVariant = LTOVariant.getValue();
else
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
A->getAsString(Args), A->getValue());
}

if (TC.getTriple().isOSWindows()) {
if (const Arg *A = Args.getLastArg(options::OPT_libc)) {
OI.RuntimeVariant =
Expand Down Expand Up @@ -2113,15 +2128,17 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
MergeModuleAction = C.createAction<MergeModuleJobAction>(AllModuleInputs);
}

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

if (OI.LinkAction == LinkKind::StaticLibrary) {
LinkAction = C.createAction<StaticLinkJobAction>(AllLinkerInputs,
OI.LinkAction);
OI.LinkAction);
} else {
LinkAction = C.createAction<DynamicLinkJobAction>(AllLinkerInputs,
OI.LinkAction);
OI.LinkAction,
PerformLTO);
}

// On ELF platforms there's no built in autolinking mechanism, so we
Expand All @@ -2130,7 +2147,7 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
const auto &Triple = TC.getTriple();
SmallVector<const Action *, 2> AutolinkExtractInputs;
for (const Action *A : AllLinkerInputs)
if (A->getType() == file_types::TY_Object) {
if (A->getType() == OI.CompilerOutputType) {
// Shared objects on ELF platforms don't have a swift1_autolink_entries
// section in them because the section in the .o files is marked as
// SHF_EXCLUDE.
Expand All @@ -2146,7 +2163,7 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
(Triple.getObjectFormat() == llvm::Triple::ELF && !Triple.isPS4()) ||
Triple.getObjectFormat() == llvm::Triple::Wasm ||
Triple.isOSCygMing();
if (!AutolinkExtractInputs.empty() && AutolinkExtractRequired) {
if (!AutolinkExtractInputs.empty() && AutolinkExtractRequired && !PerformLTO) {
auto *AutolinkExtractAction =
C.createAction<AutolinkExtractJobAction>(AutolinkExtractInputs);
// Takes the same inputs as the linker...
Expand Down
5 changes: 5 additions & 0 deletions lib/Driver/ToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,11 @@ ToolChain::constructInvocation(const CompileJobAction &job,
Arguments.push_back("-track-system-dependencies");
}

if (auto arg = context.Args.getLastArg(options::OPT_lto)) {
Arguments.push_back(context.Args.MakeArgString(
Twine("-lto=") + arg->getValue()));
}

context.Args.AddLastArg(
Arguments,
options::
Expand Down
3 changes: 3 additions & 0 deletions lib/Driver/ToolChains.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain {
void addDeploymentTargetArgs(llvm::opt::ArgStringList &Arguments,
const JobContext &context) const;

void addLTOLibArgs(llvm::opt::ArgStringList &Arguments,
const JobContext &context) const;

void addCommonFrontendArgs(
const OutputInfo &OI, const CommandOutput &output,
const llvm::opt::ArgList &inputArgs,
Expand Down
26 changes: 25 additions & 1 deletion lib/Driver/UnixToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation(

addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_Object);
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_LLVM_BC);
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);

Arguments.push_back("-o");
Arguments.push_back(
Expand Down Expand Up @@ -167,6 +170,9 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
std::string Linker;
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
Linker = A->getValue();
} else if (context.OI.LTOVariant != OutputInfo::LTOKind::None) {
// Force to use lld for LTO
Linker = "lld";
} else {
Linker = getDefaultLinker();
}
Expand Down Expand Up @@ -218,6 +224,16 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
Arguments.push_back("-pie");
}

switch (context.OI.LTOVariant) {
case OutputInfo::LTOKind::LLVMThin:
Arguments.push_back("-flto=thin");
break;
case OutputInfo::LTOKind::LLVMFull:
Arguments.push_back("-flto=full");
break;
case OutputInfo::LTOKind::None: break;
}

bool staticExecutable = false;
bool staticStdlib = false;

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

addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_Object);
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_LLVM_BC);
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);


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

// Configure the toolchain.
const char *AR = "ar";
const char *AR = "llvm-ar";
Arguments.push_back("crs");

Arguments.push_back(
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));

addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_Object);
addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_LLVM_BC);
addInputsOfType(Arguments, context.InputActions, file_types::TY_Object);
addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC);


InvocationInfo II{AR, Arguments};

Expand Down
Loading