-
Notifications
You must be signed in to change notification settings - Fork 157
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
Default handlers get mono-morphized needlessly #19
Comments
Not that I know of. I was hoping LLVM would merge the identical functions but it doesn't. I don't know if it's capable of doing that at all. cc @eddyb Do you know if LLVM should be able to optimize something like this and we are not giving it enough information or maybe it's not possible to do at all: extern "C" fn default_handler<T>(_: T) {
// code that doesn't use `T` at all
}
struct Foo;
struct Bar;
struct Baz;
struct Quux;
#[repr(C)]
struct Exceptions {
foo: extern "C" fn(Foo),
bar: extern "C" fn(Bar),
baz: extern "C" fn(Baz),
quux: extern "C" fn(Quux),
}
#[no_mangle]
pub static _EXCEPTIONS: Exceptions = Exceptions {
foo: default_handler,
bar: default_handler,
baz: default_handler,
quux: default_handler,
}; Today, we get something like this (release + LTO):
Ideally, we'd like something like this:
|
@japaric You need |
Thanks for the suggestion, @eddyb. Unfortunately, it didn't work. We were already using |
Running a debug
etc. Well, turns out it's a FIXME in LLVM: // Don't merge tiny functions, since it can just end up making the function
// larger.
// FIXME: Should still merge them if they are unnamed_addr and produce an
// alias.
if (NewFunction->size() == 1) {
if (NewFunction->front().size() <= 2) {
DEBUG(dbgs() << NewFunction->getName()
<< " is to small to bother merging\n");
return false;
}
} I've looked it and it seems very straightforward to fix. Take the logic from |
Another fix has been proposed in rust-embedded/cortex-m-rt#27 and rust-embedded/svd2rust#130. It uses |
Hello, @whitequark! Any updates on your patches? I think they can also save some space on panic handlers as well. For each panic in a program there is a separate function that just calls the panic_fmt
For example AT2XT project by @cr1901, has 5 of this functions, and that is too much. |
But the workaround hack will give 4 bytes shorter result :) |
@pftbest The proper solution may well benefit other functions. |
Agreed, but using a hack for this specific case will not cancel the benefits of a proper solution. |
I think weak aliases is the way to solve this. Semantically it is what we want to do: unless overriden a handler will be the DEFAULT_HANDLER. The need for Relying on LLVM to merge exactly looking function works too but requires explicitly enabling the LLVM pass -- it's not enabled by default, right? -- and may not work (well) if not compiling with optimizations; I haven't actually tested that scenario. Whereas weak aliases work regardless of the optimization settings. Of course, making mergefunc better is a welcome addition. It might help in other cases like in the panicking stuff that @pftbest mentioned. |
Take a look at the code generated with svd2rust that's built without optimizations. |
I suspect that it can actually produce better results if enabled in rustc in general, given how many functions may well monomorphize to the same thing. For example, every single time you have phantom types. |
@japaric I'd love to see that patch landing. I was looking into this the other day as well but obviously you were quicker. ;) |
AFAIK, mergefunc is enabled at |
@eddyb Well, I certainly do see a difference between |
@therealprof I can't land these patches until rust-lang/rust#43313 makes it way into the nightly channel. Otherwise we'll hit LLVM assertions. |
@japaric I'm pretty sure LLVM just has a list of passes and you can add as many copies of anything as you'd like (some might break because the IR isn't what they expect but that's it). |
The global_asm! fix has landed and it's available in cortex-m-rt v0.3.5 and svd2rust v0.11.2. Note that you'll need to nightly-2017-07-21 or newer if targetting the Cortex-M architecture (or you'll hit an LLVM assertion). If these changes cause problems in the future we can always revert them as they are not part of the public / user-facing API. |
Hello, @whitequark . Any news on your patches? |
@pftbest Yes, I got some of them merged upstream, but the others seem to fail tests in weird ways. I have this on my TODO list and will return to it shortly. |
@whitequark that is great, thank you! global_asm hack didn't work that well, and we still have an extra function in binary, so it's not saving us any space compared to your solution. |
@japaric in light of above: reopen this? |
Well, the issue is fixed for now, the question is do we want to remove dependency on global_asm (and go back to naked functions, which is also not ideal, but already used for other things) when @whitequark 's patches will be merged. |
I don't think we should reopen this issue as the problem is already 99% fixed and changing the underlying solution will at most reduce binary size by 4 or 8 bytes (I forget the exact number). However, in general, I'm 👍 on reducing the number of unstable features this crate, and the whole cortex-m stack, uses so we can open an issue about that (reducing unstable features) and list the global_asm -> naked_function switch there. |
@pftbest All done. |
[RFC] default panic! to abort, drop panic-* features, add panic_fmt! macro
Since #17, identical copies of
exception::default_handler
get included in the binary, thanks to the token generic parameter. It's not a lot of code, but it seems a bit unfortunate. Is there any way around this?Thanks for all the work you do for embedded Rust, btw! <3
The text was updated successfully, but these errors were encountered: