-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[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
[LTO] Support LLVM LTO for driver #32430
Conversation
332eacb
to
6fca6d9
Compare
6fca6d9
to
9a2c341
Compare
217bd5d
to
a27e316
Compare
092dfa9
to
fb185b1
Compare
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"; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
test/Driver/link-time-opt.swift
Outdated
// 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this 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.
lib/Driver/DarwinToolChains.cpp
Outdated
llvm::sys::path::remove_filename(LTOLibPath); // 'clang' | ||
llvm::sys::path::remove_filename(LTOLibPath); // 'bin' | ||
llvm::sys::path::append(LTOLibPath, "lib", "libLTO.dylib"); | ||
|
There was a problem hiding this comment.
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.
lib/Driver/Driver.cpp
Outdated
@@ -1785,6 +1787,19 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, | |||
|
|||
} | |||
|
|||
if (const Arg *A = Args.getLastArg(options::OPT_lto)) { |
There was a problem hiding this comment.
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.
lib/Driver/Driver.cpp
Outdated
llvm::StringSwitch<Optional<OutputInfo::LTOKind>>(A->getValue()) | ||
.Case("llvm-thin", OutputInfo::LTOKind::LLVMThin) | ||
.Case("llvm-full", OutputInfo::LTOKind::LLVMFull) | ||
.Default(llvm::None); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
.
lib/Driver/Driver.cpp
Outdated
@@ -2119,15 +2134,16 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions, | |||
MergeModuleAction = C.createAction<MergeModuleJobAction>(AllModuleInputs); | |||
} | |||
|
|||
auto shouldPerformLTO = Args.hasArg(options::OPT_lto); |
There was a problem hiding this comment.
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?
lib/Driver/ToolChains.cpp
Outdated
@@ -522,6 +522,11 @@ ToolChain::constructInvocation(const CompileJobAction &job, | |||
Arguments.push_back("-track-system-dependencies"); | |||
} | |||
|
|||
if (auto arg = context.Args.getLastArg(options::OPT_lto)) { |
There was a problem hiding this comment.
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.)
lib/Driver/UnixToolChains.cpp
Outdated
@@ -368,15 +388,18 @@ toolchains::GenericUnix::constructInvocation(const StaticLinkJobAction &job, | |||
ArgStringList Arguments; | |||
|
|||
// Configure the toolchain. | |||
const char *AR = "ar"; | |||
const char *AR = "llvm-ar"; |
There was a problem hiding this comment.
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?
lib/Driver/UnixToolChains.cpp
Outdated
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)) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
lib/Driver/WindowsToolChains.cpp
Outdated
if (Linker.empty()) | ||
Arguments.push_back("-fuse-ld=lld"); |
There was a problem hiding this comment.
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.
eddd307
to
f6ee152
Compare
When LTO, frontend always emit bitcode, so ignoring bitcode embedding is expected behavior. Thanks for letting me know that case. |
f6ee152
to
936f379
Compare
Could you trigger CI for all platforms? |
@swift-ci please test |
@swift-ci please test Windows platform |
Hmm, the window CI failed due to a broken zipfile. I think it's worth triggering again.
|
@swift-ci please test Windows platform |
dfa46b6
to
af3ee50
Compare
@swift-ci please test Windows platform |
@swift-ci please test |
Build failed |
Build failed |
There was a problem hiding this 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.
lib/Driver/WindowsToolChains.cpp
Outdated
@@ -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"); |
There was a problem hiding this comment.
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?
lib/Driver/Driver.cpp
Outdated
@@ -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) { |
There was a problem hiding this comment.
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?
Would reviews from anyone else be needed before this can be merged? (Assuming that pending comments are resolved) |
af3ee50
to
c16c007
Compare
@brentdax Thanks for review again. I addressed commented points. And thank you @MaxDesiatov for facilitating review. |
@swift-ci please test |
Build failed |
Build failed |
@swift-ci please test Windows platform |
lib/Driver/Driver.cpp
Outdated
A->getAsString(Args), A->getValue()); | ||
} | ||
|
||
auto LinkerInputType = OI.LTOVariant != OutputInfo::LTOKind::None |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
c16c007
to
d6cddaa
Compare
@swift-ci please test |
@swift-ci please test Windows platform |
@compnerd thanks for the review. Would you mind having another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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.