-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Consider using available_externally linkage for cross-crate inlined functions #10212
Comments
This would result in an overall code size increase, because LLVM would have to emit external symbols for lots of small functions in the source crate. |
From my understanding, we currently already emit the symbols for all |
They shouldn't be output as external symbols, it's a bug. The reachability code doesn't work at all. |
I think it's a huge mistake to be having programmers making manual decisions about when to use inlining. The crate model is fundamentally broken and doesn't provide either the ability to expose a stable ABI or have good performance/size. |
On Thu, Oct 31, 2013 at 06:28:42PM -0700, Daniel Micay wrote:
In the end crates are really oriented around dynamic linking. We However, there are other use cases where performance is more
I'm not sure why you say that crates don't provide the ability to I am... amenable to reining in reflection or even removing it |
One thing: for generic functions, there may not be an externally |
@nikomatsakis: Rust suffers from the same problems as C++ when it comes to dynamic linking but also makes life harder. In both languages, field privacy leads to exposing the size of every public type as part of the ABI. In Rust, visit glue also exposes all the internal details of every field reachable from a public type. The definitions of global values are also serialized to metadata. C++ has instantiations of generics, but allows exporting specific instances of them. It contains anything relevant to the ABI in a header file, so it's obvious what you're exposing. The most widely used open-source C++ standard library (libstdc++) has kept binary compatibility since 2006. I don't think we'll ever reach the point where you can upgrade Rust itself or idiomatic libraries and not end up having to rebuild everything using them. However, I think it is important to support writing a stable ABI. I guess it might make more sense to be using The issue I have with If we decided to use static linking for debug builds and link-time optimization for release builds, we could pretty much stop worrying about |
A normal C library is composed of hundreds of compilation units handled via static linking or link-time optimization, and then presents a single static/dynamic library to users. If we moved towards that, it would definitely be an improvement, but I don't see much value in a top-level dynamically linkable shared object for Rust. Java is essentially doing the same thing as link-time optimization path, where each compilation unit is translated/optimized in advance to bytecode and then loaded/optimized again. There's no need for ABI compatibility in that paradigm. |
I came up with a concrete plan for this: #14527 |
In rust, a static variable is essentially the same thing as a
#define
, and to achieve the same sort of optimizations about knowing the symbol at compile time we use theavailable_externally
linkage from LLVM. What this means is that the source crate defining a static will always compile the version of the static into its own data section of the executable.When an external crate then links to this source crate, it will import statics as they're used. Each static is imported in a manner like:
Where
original.source.name
is the name of the symbol in original crate, and3
is the actual value of the constant. What this means is that LLVM can optimize based on the value of the constant (because we specify it explicitly, we loaded it from the serialized ast of the external crate). The reason we do this is so that a static has one and only one address. Theavailable_externally
linkage means that no symbol will be emitted into the crate. If LLVM determines that it needs the symbol (such as you took the address of the static), then it will link against it, otherwise LLVM optimizes it all out.In theory, we could also apply this
available_externally
optimization to functions as well. What this would mean is that the source crate would provide definitions for all#[inline]
functions, and then all crates linking against this crate would useavailable_externally
. I would hope that this meant that LLVM would attempt to inline the function, but if LLVM didn't decide to inline the function it wouldn't recompile it or emit a symbol for it.In theory this means smaller crates because all non-inlined calls to an
#[inline]
function would result in cross-crate calls.I'm a little doubtful that this would provide an actual size benefit, and I'm also unsure of whether LLVM would even optimize like this. I'm only taking my vague understanding of the linkage mode and applying it to what seems reasonable for functions. Regardless, this may be an interesting project for anyone wishing to really take a bite out of dealing with LLVM, learning compiler internals, and possibly providing a nice reduction in binary size without losing any performance.
The text was updated successfully, but these errors were encountered: