Skip to content

[LTO] Support LLVM LTO for driver #32430

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 1 commit into from
Sep 18, 2020
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
8 changes: 6 additions & 2 deletions include/swift/Driver/Action.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,16 +328,20 @@ class GeneratePCHJobAction : public JobAction {
class DynamicLinkJobAction : public JobAction {
virtual void anchor();
LinkKind Kind;
bool ShouldPerformLTO;

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

LinkKind getKind() const { return Kind; }

bool shouldPerformLTO() const { return ShouldPerformLTO; }

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 @@ -101,6 +101,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
42 changes: 35 additions & 7 deletions lib/Driver/DarwinToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,19 @@ static bool findXcodeClangPath(llvm::SmallVectorImpl<char> &path) {
return !path.empty();
}

static bool findXcodeClangLibPath(const Twine &libName,
llvm::SmallVectorImpl<char> &path) {
assert(path.empty());

if (!findXcodeClangPath(path)) {
return false;
}
llvm::sys::path::remove_filename(path); // 'clang'
llvm::sys::path::remove_filename(path); // 'bin'
llvm::sys::path::append(path, "lib", libName);
return true;
}

static void addVersionString(const ArgList &inputArgs, ArgStringList &arguments,
unsigned major, unsigned minor, unsigned micro) {
llvm::SmallString<8> buf;
Expand Down Expand Up @@ -239,12 +252,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 @@ -274,11 +290,7 @@ static void findARCLiteLibPath(const toolchains::Darwin &TC,
// If we don't have a 'lib/arc/' directory, find the "arclite" library
// relative to the Clang in the active Xcode.
ARCLiteLib.clear();
if (findXcodeClangPath(ARCLiteLib)) {
llvm::sys::path::remove_filename(ARCLiteLib); // 'clang'
llvm::sys::path::remove_filename(ARCLiteLib); // 'bin'
llvm::sys::path::append(ARCLiteLib, "lib", "arc");
}
findXcodeClangLibPath("arc", ARCLiteLib);
}
}

Expand Down Expand Up @@ -307,6 +319,15 @@ toolchains::Darwin::addArgsToLinkARCLite(ArgStringList &Arguments,
}
}

void toolchains::Darwin::addLTOLibArgs(ArgStringList &Arguments,
const JobContext &context) const {
llvm::SmallString<128> LTOLibPath;
if (findXcodeClangLibPath("libLTO.dylib", LTOLibPath)) {
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 @@ -761,6 +782,10 @@ toolchains::Darwin::constructInvocation(const DynamicLinkJobAction &job,

addArgsToLinkARCLite(Arguments, context);

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

for (const Arg *arg :
context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) {
Arguments.push_back("-F");
Expand Down Expand Up @@ -828,14 +853,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
39 changes: 29 additions & 10 deletions lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1433,12 +1433,29 @@ 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 {

if (const Arg *A = Args.getLastArg(options::OPT_lto)) {
auto LTOVariant =
llvm::StringSwitch<Optional<OutputInfo::LTOKind>>(A->getValue())
.Case("llvm-thin", 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());
}

auto CompilerOutputType = OI.LTOVariant != OutputInfo::LTOKind::None
? 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;
: CompilerOutputType;

if (const Arg *A = Args.getLastArg(options::OPT_num_threads)) {
if (BatchMode) {
Expand Down Expand Up @@ -1468,14 +1485,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 = CompilerOutputType;
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 = CompilerOutputType;
break;

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

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

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

// On ELF platforms there's no built in autolinking mechanism, so we
Expand All @@ -2149,9 +2167,10 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
AutolinkExtractInputs.push_back(A);
}
const bool AutolinkExtractRequired =
(Triple.getObjectFormat() == llvm::Triple::ELF && !Triple.isPS4()) ||
Triple.getObjectFormat() == llvm::Triple::Wasm ||
Triple.isOSCygMing();
((Triple.getObjectFormat() == llvm::Triple::ELF && !Triple.isPS4()) ||
Triple.getObjectFormat() == llvm::Triple::Wasm ||
Triple.isOSCygMing()) &&
!shouldPerformLTO;
if (!AutolinkExtractInputs.empty() && AutolinkExtractRequired) {
auto *AutolinkExtractAction =
C.createAction<AutolinkExtractJobAction>(AutolinkExtractInputs);
Expand Down
15 changes: 15 additions & 0 deletions lib/Driver/ToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,19 @@ static bool addOutputsOfType(ArgStringList &Arguments,
return Added;
}

static void addLTOArgs(const OutputInfo &OI, ArgStringList &arguments) {
switch (OI.LTOVariant) {
case OutputInfo::LTOKind::None:
break;
case OutputInfo::LTOKind::LLVMThin:
arguments.push_back("-lto=llvm-thin");
break;
case OutputInfo::LTOKind::LLVMFull:
arguments.push_back("-lto=llvm-full");
break;
}
}

void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
const CommandOutput &output,
const ArgList &inputArgs,
Expand Down Expand Up @@ -284,6 +297,8 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
arguments.push_back(inputArgs.MakeArgString(workingDirectory));
}

addLTOArgs(OI, arguments);

// -g implies -enable-anonymous-context-mangled-names, because the extra
// metadata aids debugging.
if (inputArgs.hasArg(options::OPT_g)) {
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
34 changes: 32 additions & 2 deletions 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 @@ -165,9 +168,18 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,

// Select the linker to use.
std::string Linker;
if (context.OI.LTOVariant != OutputInfo::LTOKind::None) {
// Force to use lld for LTO on Unix-like platform (not including Darwin)
// because we don't support gold LTO or something else except for lld LTO
// at this time.
Linker = "lld";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we force the use of lld here? Will this run on Darwin? On Darwin we definitely want to use ld64.

Copy link
Member Author

@kateinoigakukun kateinoigakukun Jul 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will run on Unix-like platform (Linux, Android or etc not including Darwin). And on these platforms, we don't support gold LTO or something else LTO except for lld. So I forced the use of lld here.

For example, gold LTO needs libLLVMGold.so but we don't have it in swift toolchain and it's licensed under GPL, so it's a little complex problem.

At this time, I only support lld on Unix-like platforms and those other linkers may be supported in the future.

}

if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
Linker = A->getValue();
} else {
}

if (Linker.empty()) {
Linker = getDefaultLinker();
}
if (!Linker.empty()) {
Expand Down Expand Up @@ -218,6 +230,17 @@ 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 +276,10 @@ 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 +394,19 @@ toolchains::GenericUnix::constructInvocation(const StaticLinkJobAction &job,
ArgStringList Arguments;

// Configure the toolchain.
const char *AR = "ar";
const char *AR =
context.OI.LTOVariant != OutputInfo::LTOKind::None ? "llvm-ar" : "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
21 changes: 21 additions & 0 deletions lib/Driver/WindowsToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,24 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
Linker = A->getValue();
}

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;
}

if (Linker.empty() && context.OI.LTOVariant != OutputInfo::LTOKind::None) {
// Force to use lld for LTO on Windows because we don't support link LTO or
// something else except for lld LTO at this time.
Linker = "lld";
}

if (!Linker.empty())
Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker));

Expand Down Expand Up @@ -143,7 +161,10 @@ toolchains::Windows::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
Loading