-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[LTO] Support LLVM LTO for IRGen and frontend #32429
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 IRGen and frontend #32429
Conversation
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 need some changes here. I want to go back through this again after you have responded to my comments. The big issue I have with this patch overall is that the special case handling code is /all/ over the patch. Generally, one wants the special case handling conditional code to be in one place so it is easy to find. My comments on this PR are basically around making the code easier to read/understand.
lib/IRGen/IRGenModule.cpp
Outdated
(TargetInfo.OutputObjectFormat == llvm::Triple::ELF && !Triple.isPS4()) || | ||
TargetInfo.OutputObjectFormat == llvm::Triple::Wasm || | ||
Triple.isOSCygMing(); | ||
((TargetInfo.OutputObjectFormat == llvm::Triple::ELF && |
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 you extract this into a helper function and eliminate the variable. My suggestion:
bool doesTargetAutolinkUsingAutolinkExtract(...)
I would also use early returns to make it easier to read the code. E.x.:
if (Triple.isOSCygMing()) {
return ...
}
...
lib/IRGen/IRGenModule.cpp
Outdated
@@ -1188,7 +1198,15 @@ static bool isFirstObjectFileInModule(IRGenModule &IGM) { | |||
void IRGenModule::emitAutolinkInfo() { | |||
// Collect the linker options already in the module (from ClangCodeGen). | |||
// FIXME: This constant should be vended by LLVM somewhere. | |||
auto *Metadata = Module.getOrInsertNamedMetadata("llvm.linker.options"); | |||
// When performing LTO, we always use lld that supports auto linking mechanism |
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.
If we are going to do this, there needs to be an assert somewhere that this is true.
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.
The frontend can't know which linker is used, so I'll assert it in driver
lib/IRGen/IRGenModule.cpp
Outdated
// When performing LTO, we always use lld that supports auto linking mechanism | ||
// with ELF. So embed dependent libraries names in "llvm.dependent-libraries" | ||
// instead of "llvm.linker.options". | ||
const StringRef AutolinkSectionName = |
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 would extract this out into a helper. Also const on a value type doesn't do anything. StringRef doesn't allow for the data it points to to be modified. In fact, we could even create a helper called getAutolinkSectionNameMetadata(...).
In fact, looking at this it seems that these are two ways of specifying at the llvm-ir auto link like things with dependent-libraries being slightly more constrained. Why not represent that explicitly via an enum. My thought is you would have 3 enum values: llvm.dependent-libraries, llvm linker options native, llvm linker options swift auto link extract.
lib/IRGen/IRGenModule.cpp
Outdated
// mechanism with ELF. So embed dependent libraries names in | ||
// "llvm.dependent-libraries" instead of options to avoid using | ||
// swift-autolink-extract. | ||
AutolinkEntries.push_back( |
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 really dislike that this is being done here in this way. It leaks an implementation detail. Why not change AutolinkEntries to instead of taking an MDNode, take a type called:
struct AutolinkEntry {
PointerIntPair<llvm::MDNode *, 1> mdNodeOrLibName;
}
Then you can use the lib name as a discriminator and move this code to emitAutolinkInfo maybe in a helper function. Your thoughts?
e23c5a9
to
c1ea01b
Compare
lib/IRGen/IRGenModule.cpp
Outdated
} | ||
|
||
namespace { | ||
enum class AutolinkKind { |
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.
The nice way of doing this would be to use a struct enum pattern. The way you do this is that you:
struct AutolinkKind {
enum ValueTy {
...
};
ValueTy value;
AutolinkKind(ValueTy value) : Value(value) {}
AutolinkKind(const AutolinkKind &kind) : Value(kind.value) {}
}
Then you can sink a lot of this logic into method names on Autolink. In fact you could even have private constructors and make determining the Kind a class method that selects the relevant value.
f806bc4
to
41f730b
Compare
@gottesmm I addressed commented points. Could you review again? |
lib/IRGen/IRGenModule.cpp
Outdated
llvm::LLVMContext &ctx = Module.getContext(); | ||
|
||
// Construct autolinking entries | ||
switch (Autolink) { |
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 you sink this into the AutolinkKind type. I shouldn't see any switches inline here.
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.
👍
f30bfb0
to
2207677
Compare
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 is starting to look really nice! I really like how you separated the lower level logic onto the enum! It makes it so much clearer about what the code is actually trying to do!
I put in a bunch of comments where there are breakage of LLVM style around control flow. Can you please fix those?
lib/IRGen/IRGenModule.cpp
Outdated
switch (Value) { | ||
case AutolinkKind::LLVMDependentLibraries: | ||
return "llvm.dependent-libraries"; | ||
break; |
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.
You don't need a break here.
I agree that these constants should be in LLVM (probably constexpr StringLiterals).
lib/IRGen/IRGenModule.cpp
Outdated
case AutolinkKind::LLVMLinkerOptions: | ||
case AutolinkKind::SwiftAutoLinkExtract: | ||
return "llvm.linker.options"; | ||
break; |
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.
Also you do not need this break.
2207677
to
c45d2e6
Compare
lib/IRGen/IRGenModule.cpp
Outdated
case LibraryKind::Framework: { | ||
llvm_unreachable( | ||
"llvm.dependent-libraries doesn't support framework dependency"); | ||
return; |
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 think you need a return here.
c45d2e6
to
e444039
Compare
lib/IRGen/IRGenModule.cpp
Outdated
} | ||
|
||
void AutolinkKind::writeEntries( | ||
const llvm::SmallVector<llvm::MDNode *, 4> &Entries, |
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.
If you aren't going to actually write to this, I would change it to be an ArrayRef<llvm::MDNode *>. This is more general and doesn't have the small vector size in the type.
If one needed to append to the array, the way people do it is that they use:
SmallVectorImpl<llvm::MDNode *> &Entries
that way we avoid encoding the 4. That being said I think this is an immutable use here, so this is just an FYI.
lib/IRGen/IRGenModule.cpp
Outdated
} | ||
|
||
void AutolinkKind::collectEntriesFromLibraries( | ||
llvm::SmallVector<llvm::MDNode *, 4> &Entries, |
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 is where I think one would use a SmallVectorImpl. Also, llvm:: is embedded into the swift namespace so you don't need llvm::.
lib/IRGen/IRGenModule.cpp
Outdated
|
||
void AutolinkKind::collectEntriesFromLibraries( | ||
llvm::SmallVector<llvm::MDNode *, 4> &Entries, | ||
const SmallVector<LinkLibrary, 32> &AutolinkEntries, IRGenModule &IGM) { |
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.
AutolinkEntries on the other hand, should be an ArrayRef.
e444039
to
d49c266
Compare
include/swift/AST/IRGenOptions.h
Outdated
@@ -65,6 +65,8 @@ enum class IRGenDebugInfoFormat : unsigned { | |||
CodeView | |||
}; | |||
|
|||
enum class IRGenLLVMLTOKind : unsigned { None, Thin, Full }; |
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.
Too bad clang-format does this. I may try to fix this at some point. Don't worry about it though. Not on you.
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.
FYI, adding trailing comma after Full
results:
enum class IRGenLLVMLTOKind : unsigned {
None,
Thin,
Full,
};
40c087f
to
a3976d4
Compare
lib/IRGen/IRGenModule.cpp
Outdated
|
||
void AutolinkKind::collectEntriesFromLibraries( | ||
SmallVectorImpl<llvm::MDNode *> &Entries, | ||
const ArrayRef<LinkLibrary> &AutolinkEntries, IRGenModule &IGM) { |
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.
ArrayRef is a value type that refers to an unowned const array. You don't need const or to pass by reference.
ef6d6c8
to
8c8cd28
Compare
lib/IRGen/IRGenModule.cpp
Outdated
StringRef AutolinkSectionName = Autolink.getSectionNameMetadata(); | ||
|
||
auto *Metadata = Module.getOrInsertNamedMetadata(AutolinkSectionName); | ||
llvm::SetVector<llvm::MDNode *> Entries; |
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 think this was a SmallVector before, no? Why not make a SmallSetVector? Or maybe my memory is wrong.
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.
Ah, yes. I restored to use SmallSetVector
faa7adc
to
f617fed
Compare
I added some cases around clang importer things |
@gottesmm sorry for pinging you. Could you take a look again? |
lib/IRGen/IRGenModule.cpp
Outdated
static AutolinkKind create(const SwiftTargetInfo &TargetInfo, | ||
llvm::Triple Triple, IRGenLLVMLTOKind LLVMLTOKind); | ||
}; | ||
} // namespace |
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 you put a newline in between };
and the }
. Can you change // namespace -> // anonymous namespace.?
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.
Updated 👍
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.
Make that small change and then LGTM!
f617fed
to
c1ca57f
Compare
@swift-ci please test |
Build failed |
Build failed |
c1ca57f
to
20bc0af
Compare
This commit adds -lto flag for frontend to enable LTO at LLVM level. When -lto=llvm given, compiler emits LLVM bitcode file instead of object file and adds index summary for LTO. In addition for ELF format, emit llvm.dependent-libraries section to embed auto linking information
It seems the failing test case |
@swift-ci please test |
Build failed |
Build failed |
The tests didnt trigger on the windows builder - this seems to be causing a windows test failure: https://ci-external.swift.org/job/oss-swift-windows-x86_64-vs2019/1968/ |
The test was overly strict in checking the IR, loosen the test appropriately.
This commit adds -lto flag for frontend to enable LTO at LLVM level.
When -lto=llvm given, compiler emits LLVM bitcode file instead of object
file and adds index summary for LTO.
In addition for ELF format, emit llvm.dependent-libraries section to
embed auto linking information
This is pulled out from #32237
CC: @compnerd @gottesmm
Replace this paragraph with a description of your changes and rationale. Provide links to external references/discussions if appropriate.
Resolves SR-NNNN.