Skip to content

Commit

Permalink
[LTO] Support LLVM LTO for driver
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kateinoigakukun committed Jul 31, 2020
1 parent 063d420 commit d6cddaa
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 21 deletions.
8 changes: 6 additions & 2 deletions include/swift/Driver/Action.h
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
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
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
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
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
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
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";
}

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

0 comments on commit d6cddaa

Please sign in to comment.