Skip to content

[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

Merged

Conversation

kateinoigakukun
Copy link
Member

@kateinoigakukun kateinoigakukun commented Jun 17, 2020

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.

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.

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.

(TargetInfo.OutputObjectFormat == llvm::Triple::ELF && !Triple.isPS4()) ||
TargetInfo.OutputObjectFormat == llvm::Triple::Wasm ||
Triple.isOSCygMing();
((TargetInfo.OutputObjectFormat == llvm::Triple::ELF &&
Copy link
Contributor

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

@@ -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
Copy link
Contributor

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.

Copy link
Member Author

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

// 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 =
Copy link
Contributor

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.

// mechanism with ELF. So embed dependent libraries names in
// "llvm.dependent-libraries" instead of options to avoid using
// swift-autolink-extract.
AutolinkEntries.push_back(
Copy link
Contributor

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?

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch from e23c5a9 to c1ea01b Compare June 18, 2020 06:51
}

namespace {
enum class AutolinkKind {
Copy link
Contributor

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.

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch 3 times, most recently from f806bc4 to 41f730b Compare June 18, 2020 07:53
@kateinoigakukun
Copy link
Member Author

@gottesmm I addressed commented points. Could you review again?

llvm::LLVMContext &ctx = Module.getContext();

// Construct autolinking entries
switch (Autolink) {
Copy link
Contributor

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

👍

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch 2 times, most recently from f30bfb0 to 2207677 Compare June 20, 2020 06:14
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.

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?

switch (Value) {
case AutolinkKind::LLVMDependentLibraries:
return "llvm.dependent-libraries";
break;
Copy link
Contributor

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

case AutolinkKind::LLVMLinkerOptions:
case AutolinkKind::SwiftAutoLinkExtract:
return "llvm.linker.options";
break;
Copy link
Contributor

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.

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch from 2207677 to c45d2e6 Compare June 21, 2020 02:54
case LibraryKind::Framework: {
llvm_unreachable(
"llvm.dependent-libraries doesn't support framework dependency");
return;
Copy link
Contributor

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.

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch from c45d2e6 to e444039 Compare June 21, 2020 03:03
}

void AutolinkKind::writeEntries(
const llvm::SmallVector<llvm::MDNode *, 4> &Entries,
Copy link
Contributor

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.

}

void AutolinkKind::collectEntriesFromLibraries(
llvm::SmallVector<llvm::MDNode *, 4> &Entries,
Copy link
Contributor

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


void AutolinkKind::collectEntriesFromLibraries(
llvm::SmallVector<llvm::MDNode *, 4> &Entries,
const SmallVector<LinkLibrary, 32> &AutolinkEntries, IRGenModule &IGM) {
Copy link
Contributor

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.

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch from e444039 to d49c266 Compare June 21, 2020 03:08
@@ -65,6 +65,8 @@ enum class IRGenDebugInfoFormat : unsigned {
CodeView
};

enum class IRGenLLVMLTOKind : unsigned { None, Thin, Full };
Copy link
Contributor

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.

Copy link
Member

@rintaro rintaro Jun 24, 2020

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

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch 2 times, most recently from 40c087f to a3976d4 Compare June 21, 2020 03:15

void AutolinkKind::collectEntriesFromLibraries(
SmallVectorImpl<llvm::MDNode *> &Entries,
const ArrayRef<LinkLibrary> &AutolinkEntries, IRGenModule &IGM) {
Copy link
Contributor

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.

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch 3 times, most recently from ef6d6c8 to 8c8cd28 Compare June 21, 2020 04:27
StringRef AutolinkSectionName = Autolink.getSectionNameMetadata();

auto *Metadata = Module.getOrInsertNamedMetadata(AutolinkSectionName);
llvm::SetVector<llvm::MDNode *> Entries;
Copy link
Contributor

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.

Copy link
Member Author

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

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch 2 times, most recently from faa7adc to f617fed Compare June 24, 2020 03:04
@kateinoigakukun
Copy link
Member Author

I added some cases around clang importer things

@kateinoigakukun
Copy link
Member Author

@gottesmm sorry for pinging you. Could you take a look again?

static AutolinkKind create(const SwiftTargetInfo &TargetInfo,
llvm::Triple Triple, IRGenLLVMLTOKind LLVMLTOKind);
};
} // namespace
Copy link
Contributor

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated 👍

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.

Make that small change and then LGTM!

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch from f617fed to c1ca57f Compare June 30, 2020 23:14
@compnerd
Copy link
Member

compnerd commented Jul 1, 2020

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented Jul 1, 2020

Build failed
Swift Test Linux Platform
Git Sha - 41f730b648bc95d81575978d7e0c5ef5d6c987cb

@swift-ci
Copy link
Contributor

swift-ci commented Jul 1, 2020

Build failed
Swift Test OS X Platform
Git Sha - 41f730b648bc95d81575978d7e0c5ef5d6c987cb

@kateinoigakukun kateinoigakukun force-pushed the katei/llvm-lto-driver-part branch from c1ca57f to 20bc0af Compare July 1, 2020 23:30
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
@kateinoigakukun
Copy link
Member Author

It seems the failing test case stdlib/KeyPath.swift is not related to this change. ref: #32664

@compnerd
Copy link
Member

compnerd commented Jul 2, 2020

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented Jul 2, 2020

Build failed
Swift Test Linux Platform
Git Sha - c1ca57ff45d18459ce837777416c56f97074e7b3

@swift-ci
Copy link
Contributor

swift-ci commented Jul 2, 2020

Build failed
Swift Test OS X Platform
Git Sha - c1ca57ff45d18459ce837777416c56f97074e7b3

@kateinoigakukun
Copy link
Member Author

kateinoigakukun commented Jul 6, 2020

@compnerd @gottesmm I think this PR is ready to merge. Could you merge this?

@gottesmm gottesmm merged commit 5fa68c5 into swiftlang:master Jul 7, 2020
@compnerd
Copy link
Member

compnerd commented Jul 7, 2020

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/
https://ci-external.swift.org/job/oss-swift-windows-x86_64-vs2019/1968/consoleText

compnerd added a commit to compnerd/apple-swift that referenced this pull request Jul 7, 2020
The test was overly strict in checking the IR, loosen the test
appropriately.
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.

5 participants