Skip to content

Implement cross-language ThinLTO #49879

Closed
@michaelwoerister

Description

@michaelwoerister
Member

What is cross-language LTO?

Rust uses LLVM as its code generation backend, as does the Clang C/C++ compiler and many other languages. As a consequence, all of those LLVM-based compilers can produce artifacts that can partake in a common Link-Time-Optimization step, irrespective of the given source language. Thus, in this context, cross-language LTO means that we enable the Rust compiler to produce static libraries that can make use of LLVM-LTO-based linker plugins as exist for newer versions of ld, gold, and in lld.

Why is cross-language LTO a good thing?

In order for Rust to interoperate with code written in other languages, calls have to go through a C interface. This interface poses a boundary for inter-procedural optimizations like inlining. At the same time inter-procedural optimizations are very important for performance. Cross-language LTO makes this boundary transparent to LLVM, effectively allowing for C/C++ code to be inlined into Rust code and vice versa.

How can it be implemented?

There are several options. The basic requirement is that we emit LLVM bitcode into our object files in a format that the LLVM linker plugin can handle. There are two formats that fulfill this requirement:

  1. We emit .o files that actually aren't object files but plain LLVM bitcode files.
  2. We add the LLVM bitcode of an object file into a special .llvmbc section of the object file.

Given these requirements there are a few ways of implementing the feature:

  1. Always emit bitcode into object files instead of storing them as separate files in RLIBs

    • Pros
      • simple for users, it just works
      • this is something that some platforms, like IOS, want to have anyway
    • Cons
      • staticlibs would contain bitcode, even though it might not be needed
      • the Rust compiler would have to be modified to read bitcode out of a section instead of separate obj-file
      • we could not store bitcode compressed anymore
  2. Just stabilize -Z embed-bitcode and require users to do the rest

    • Pros
      • simple to implement
    • Cons
      • harder to use (needs user intervention)
      • unclear how to integrate with Cargo
      • RLIBs generated this way will contain bitcode twice
  3. Add a flag that makes rustc emit bitcode files instead of object files

    • Pros
      • no redundant codegen
      • no redundant machine code
    • Cons
      • harder to use (needs user intervention)
      • produces libraries that are incompatible with regular compilation, which is weird
      • even more strange special casing Rust compiler backend
      • unclear how to integrate with Cargo
  4. Add a -C cross-language-lto flag that (1) makes the compiler embed bitcode into RLIBs and static libraries, and (2) makes the compiler invoke the linker with the LLVMgold.so plugin, if applicable.

    • Pros
      • would make cross-language LTO available for binaries built with rustc
      • rustc can skip the redundant ThinLTO step for binaries and dylibs
      • RLIBs and staticlibs would be bigger but it's on an opt-in basis
    • Cons
      • since LTO is deferred to the linker, it would not be integrated with the Make jobserver
      • harder to use (needs user intervention)
      • unclear how to integrate with Cargo

I think I would opt for option (1) since it's the most straightforward to use. EDIT: Added option (4) which I also like.

cc @rust-lang/compiler @alexcrichton
(@rust-lang/wg-codegen might also be interested in this)

Activity

added
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
C-feature-requestCategory: A feature request, i.e: not implemented / a PR.
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
WG-llvmWorking group: LLVM backend code generation
on Apr 11, 2018
alexcrichton

alexcrichton commented on Apr 11, 2018

@alexcrichton
Member

I think I personally like option 4 best, although I might spin it a little differently as -C lto=cross-language or something like that. In that case rustc would do nothing for LTO other than ensuring it's ready to LTO inside the linker, and then then linker could do all the work.

michaelwoerister

michaelwoerister commented on Apr 12, 2018

@michaelwoerister
MemberAuthor

With -C lto=cross-language, would rustc take care of invoking the linker correctly (e.g. when compiling an executable)? And if so, how would rustc know whether to invoke the linker for thin or for full LTO?

alexcrichton

alexcrichton commented on Apr 12, 2018

@alexcrichton
Member

@michaelwoerister yeah I think we could try to pass all the right options by default. I'm not actually sure how you configure full/thin at the linker layer?

One neat thing we could do, though, is that if you're on MSVC, for example, we could switch to lld by default or something like that

michaelwoerister

michaelwoerister commented on Apr 13, 2018

@michaelwoerister
MemberAuthor

I'm not actually sure how you configure full/thin at the linker layer?

By passing -plugin-opt=thinlto to the linker, I think.

If we did it as -C lto=cross-language, we'd need another way of selecting thin vs full. Or have -C lto=thin-cross-language, which I find aesthetically displeasing :)

I'd love if we could shift all of LTO into the linker completely. But that would mean that we essentially can't use the MSVC linker anymore. And the Make jobserver story would regress too.

nagisa

nagisa commented on Apr 13, 2018

@nagisa
Member
alexcrichton

alexcrichton commented on Apr 13, 2018

@alexcrichton
Member

@michaelwoerister ah good point, in that case having a separate -C cross-language-lto seems fine by me (or @nagisa's idea)

michaelwoerister

michaelwoerister commented on Apr 18, 2018

@michaelwoerister
MemberAuthor

@alexcrichton, do you know how to enable building the LLVMgold.so linker plugin? When I build LLVM from SVN, it gets built automatically but for rustc's LLVM version that doesn't seem to be the case.

alexcrichton

alexcrichton commented on Apr 18, 2018

@alexcrichton
Member

Ah I've never built it myself so I'm not sure :(

111 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-feature-requestCategory: A feature request, i.e: not implemented / a PR.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.WG-llvmWorking group: LLVM backend code generation

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @Zoxc@alexcrichton@shepmaster@matthiaskrgr@nagisa

      Issue actions

        Implement cross-language ThinLTO · Issue #49879 · rust-lang/rust