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

Conversation

kateinoigakukun
Copy link
Member

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 embedded in LLVM BC content when LTO.

This is pulled out from #32237 and based on #32429

Replace this paragraph with a description of your changes and rationale. Provide links to external references/discussions if appropriate.

Resolves SR-NNNN.

@kateinoigakukun kateinoigakukun marked this pull request as draft June 17, 2020 13:49
@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch from 332eacb to 6fca6d9 Compare July 7, 2020 23:31
@kateinoigakukun kateinoigakukun marked this pull request as ready for review July 7, 2020 23:31
@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch from 6fca6d9 to 9a2c341 Compare July 8, 2020 00:55
@kateinoigakukun kateinoigakukun marked this pull request as draft July 8, 2020 01:51
@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch 2 times, most recently from 217bd5d to a27e316 Compare July 8, 2020 04:59
@kateinoigakukun kateinoigakukun marked this pull request as ready for review July 8, 2020 05:10
@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch 2 times, most recently from 092dfa9 to fb185b1 Compare July 8, 2020 07:21
@gottesmm
Copy link
Contributor

gottesmm commented Jul 9, 2020

I am not a driver person so I am asking around for a driver person to look at this.

if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
if (context.OI.LTOVariant != OutputInfo::LTOKind::None) {
// Force to use lld for LTO
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.

// RUN: echo "int dummy;" >%t/a.cpp
// RUN: cc -c %t/a.cpp -o %t/a.o
// RUN: %swiftc_driver -save-temps -driver-print-jobs %S/../Inputs/empty.swift %t/a.o -lto=llvm-full -target x86_64-apple-macosx10.9 -driver-filelist-threshold=0 -o filelist 2>&1 | tee %t/forFilelistCapture | %FileCheck -check-prefix FILELIST %s
// RUN: tail -2 %t/forFilelistCapture | head -1 | sed 's/.*-output-filelist //' | sed 's/ .*//' > %t/output-filelist
Copy link
Contributor

Choose a reason for hiding this comment

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

I want an end to end test. Maybe in the interpreter dir. With something that LTO can hit for sure.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added dead symbol strip e2e test case

Copy link
Contributor

@beccadax beccadax left a comment

Choose a reason for hiding this comment

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

I don't know much about how LTO linking works, but I can comment on driver structure.

In addition to the inline comments, please take a look at validateEmbedBitcode() and think about whether file_types::TY_LLVM_BC ought to now be valid there.

llvm::sys::path::remove_filename(LTOLibPath); // 'clang'
llvm::sys::path::remove_filename(LTOLibPath); // 'bin'
llvm::sys::path::append(LTOLibPath, "lib", "libLTO.dylib");

Copy link
Contributor

Choose a reason for hiding this comment

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

Would deriving this path from ToolChain::getClangLibraryPath() give you a correct path to this dylib? (Basically, will it be present in open-source toolchains, and if so, will the toolchain version be the one we want to use?)

If not, could you generalize findARCLiteLibPath() (e.g. findXcodeClangLibPath("arc", ...), findXcodeClangLibPath("libLTO.dylib", ...)) and then use the general form here? That would reduce duplication.

@@ -1785,6 +1787,19 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,

}

if (const Arg *A = Args.getLastArg(options::OPT_lto)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than reading OPT_lto twice, why don't we move this up top and integrate it with setting LinkerInputType and/or OI.CompilerOutputType? That will ensure consistency even if we diagnose an error.

llvm::StringSwitch<Optional<OutputInfo::LTOKind>>(A->getValue())
.Case("llvm-thin", OutputInfo::LTOKind::LLVMThin)
.Case("llvm-full", OutputInfo::LTOKind::LLVMFull)
.Default(llvm::None);
Copy link
Contributor

Choose a reason for hiding this comment

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

How does LTOKind::None get set? Is it just the default? Should it be possible to set it explicitly?

Copy link
Member Author

Choose a reason for hiding this comment

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

LTOKind::None is the default kind and it means that driver didn't get -lto= option.
In this switch statement, llvm::None means that driver got invalid lto mode string and it's different from LTOKind::None.

@@ -2119,15 +2134,16 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
MergeModuleAction = C.createAction<MergeModuleJobAction>(AllModuleInputs);
}

auto shouldPerformLTO = Args.hasArg(options::OPT_lto);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we read this information out of OI.LTOVariant instead of looking for OPT_lto again?

@@ -522,6 +522,11 @@ ToolChain::constructInvocation(const CompileJobAction &job,
Arguments.push_back("-track-system-dependencies");
}

if (auto arg = context.Args.getLastArg(options::OPT_lto)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we read this information out of context.OI.LTOVariant instead of looking for OPT_lto again?

Also, would it make sense to do this in addCommonFrontendArgs() instead? (If other calls to the frontend, like merge-modules and PCH building, ought to know if we're building for LTO, then it probably should be.)

@@ -368,15 +388,18 @@ toolchains::GenericUnix::constructInvocation(const StaticLinkJobAction &job,
ArgStringList Arguments;

// Configure the toolchain.
const char *AR = "ar";
const char *AR = "llvm-ar";
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this change correct for all builds, or only for LTO?

Comment on lines 168 to 174
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
if (context.OI.LTOVariant != OutputInfo::LTOKind::None) {
// Force to use lld for LTO
Linker = "lld";
} else if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Either OPT_use_ld should take precedence over this LTO-specific branch, or the combination of OPT_use_ld and OPT_lto should diagnose an error. Silently ignoring -use-ld is a bad move.

Copy link
Member Author

Choose a reason for hiding this comment

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

OK, I changed to prefer -use-ld option.

Comment on lines 195 to 196
if (Linker.empty())
Arguments.push_back("-fuse-ld=lld");
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps you should move this condition out of the switch and make it if (Linker.empty() && context.OI.LTOVariant != OutputInfo::LTOKind::None). Then you could get rid of the other if statement below and simply make the appropriate Arguments.push_back() call in each case, making the control flow much more straightforward.

For that matter, maybe you should move this all the way up to line 79 or so, where you can set Linker right before a -fuse-ld= would normally be generated, rather than adding another place it could be inserted down here and having to reason about whether or not you already did it earlier. Again, please either make OPT_use_ld "win" over this logic, or diagnose an error if you use both.

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch 2 times, most recently from eddd307 to f6ee152 Compare July 12, 2020 06:27
@kateinoigakukun
Copy link
Member Author

@brentdax

In addition to the inline comments, please take a look at validateEmbedBitcode() and think about whether file_types::TY_LLVM_BC ought to now be valid there.

When LTO, frontend always emit bitcode, so ignoring bitcode embedding is expected behavior. Thanks for letting me know that case.

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch from f6ee152 to 936f379 Compare July 12, 2020 07:27
@kateinoigakukun
Copy link
Member Author

Could you trigger CI for all platforms?

@MaxDesiatov
Copy link
Contributor

@swift-ci please test

@MaxDesiatov
Copy link
Contributor

@swift-ci please test Windows platform

@kateinoigakukun
Copy link
Member Author

Hmm, the window CI failed due to a broken zipfile. I think it's worth triggering again.

ci@SWIFTCI-WINDOWS S:\jenkins\workspace\swift-PR-windows>"C:\Program Files\Git\usr\bin\unzip.exe" -o icu4c-64_2-Win64-MSVC2017.zip -d "S:\jenkins\workspace\swift-PR-windows\icu-64_2" 
Archive:  icu4c-64_2-Win64-MSVC2017.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of icu4c-64_2-Win64-MSVC2017.zip or
        icu4c-64_2-Win64-MSVC2017.zip.zip, and cannot find icu4c-64_2-Win64-MSVC2017.zip.ZIP, period.

@MaxDesiatov
Copy link
Contributor

@swift-ci please test Windows platform

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch 2 times, most recently from dfa46b6 to af3ee50 Compare July 14, 2020 00:30
@MaxDesiatov
Copy link
Contributor

@swift-ci please test Windows platform

@MaxDesiatov
Copy link
Contributor

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 936f379ff7c260624b23f5ef5367313b91eea5e5

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 936f379ff7c260624b23f5ef5367313b91eea5e5

@swiftlang swiftlang deleted a comment from swift-ci Jul 14, 2020
@swiftlang swiftlang deleted a comment from swift-ci Jul 14, 2020
@MaxDesiatov MaxDesiatov requested review from compnerd and beccadax July 14, 2020 11:16
Copy link
Contributor

@beccadax beccadax left a comment

Choose a reason for hiding this comment

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

A couple of comments, but they might not end up requiring changes.

@@ -76,6 +76,20 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
Linker = A->getValue();
}

if (Linker.empty() && context.OI.LTOVariant != OutputInfo::LTOKind::None)
Arguments.push_back("-fuse-ld=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 don't we just set Linker here and then let the code after the switch add the flag?

@@ -2152,7 +2170,8 @@ 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 &&
!shouldPerformLTO) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does shouldPerformLTO influence the value of RequiresAutolinkExtract? Should it?

@MaxDesiatov MaxDesiatov requested a review from gottesmm July 24, 2020 21:18
@MaxDesiatov
Copy link
Contributor

MaxDesiatov commented Jul 24, 2020

Would reviews from anyone else be needed before this can be merged? (Assuming that pending comments are resolved)

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch from af3ee50 to c16c007 Compare July 25, 2020 11:29
@kateinoigakukun
Copy link
Member Author

@brentdax Thanks for review again. I addressed commented points.

And thank you @MaxDesiatov for facilitating review.

@MaxDesiatov
Copy link
Contributor

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - af3ee5084d7fa088f759b386a4ab535368a32a76

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - af3ee5084d7fa088f759b386a4ab535368a32a76

@MaxDesiatov
Copy link
Contributor

@swift-ci please test Windows platform

A->getAsString(Args), A->getValue());
}

auto LinkerInputType = OI.LTOVariant != OutputInfo::LTOKind::None
Copy link
Member

Choose a reason for hiding this comment

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

What do you think of changing this to CompilerOutputType? The linker input type is confusing since the linker should be provided both object files and bitcode.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree. Updated.

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.
@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver branch from c16c007 to d6cddaa Compare July 31, 2020 01:18
@MaxDesiatov
Copy link
Contributor

@swift-ci please test

@MaxDesiatov MaxDesiatov requested a review from compnerd July 31, 2020 11:06
@MaxDesiatov
Copy link
Contributor

@swift-ci please test Windows platform

@MaxDesiatov
Copy link
Contributor

@compnerd thanks for the review. Would you mind having another look?

@kateinoigakukun
Copy link
Member Author

@brentdax @compnerd @gottesmm Would you mind taking a look again?

@MaxDesiatov
Copy link
Contributor

@compnerd @gottesmm would you have a moment to have a look at this PR? Thank you!

Copy link
Contributor

@gottesmm gottesmm left a comment

Choose a reason for hiding this comment

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

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants