-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Uses of GlobalAlloc::realloc yield useless code in lto+opt-level=2 builds #56938
Comments
A condition in |
BTW, it's worth noting that in the original assembly, one of the calls to 32a6: 48 89 e7 mov %rsp,%rdi
32a9: be 08 00 00 00 mov $0x8,%esi
32ae: 31 d2 xor %edx,%edx
32b0: ff 15 12 2d 02 00 callq *0x22d12(%rip) # 25fc8 <posix_memalign@GLIBC_2.2.5> The signature of |
O_o this doesn't make sense. I replaced |
One thing that addresses the #[repr(align(32))]
struct Foo(u8);
fn main() {
println!("{}", std::mem::size_of::<Foo>());
} prints 32, not 1. That would need more careful consideration, though. |
About that... extern "C" {
pub fn realloc(p: *mut std::ffi::c_void, size: usize) -> *mut std::ffi::c_void;
}
pub fn foo(s: usize) -> *mut u8 {
unsafe {
realloc(std::ptr::null_mut(), s) as *mut u8
}
} compiles to example::foo:
jmp qword ptr [rip + malloc@GOTPCREL] |
FWIW, removing the |
I think we need to separate how
I think this particular branch is in Lines 674 to 680 in c9bb68f
If we made In rust/src/libstd/sys/unix/alloc.rs Lines 53 to 57 in 041254b
I think this one is necessary because:
In #45955 we found out that in practice, implementations of
I don’t know if the optimizer is aware of point 6 (as I understand it,
Does that fix #45955 ?
Would adding |
But |
I suppose a larger question is: is there any use case for an allocation request more aligned than its size? If not, should we forbid it? If so, how do we deal with existing stable APIs that do not enforce or document this constraint? (Introducing new APIs and deprecating existing ones is always an option, but should be a last resort.) |
Yes. A likely and common scenario here would be a request for a page-aligned allocation that is not necessarily spanning the whole page. |
Can you say more about how that would be used? Can allocator implementations typically do that and still use the rest of the page for other allocations? |
It is common for low-level functions to have requirements for page-size alignment. Something that comes to mind is a stack (platforms usually have their own respective alignment requirements, but page-aligned allocations are safe to use on a all known-and-relevant targets). It is heckin' convenient to be able to write
Not sure if your usual implementation of bin/buddy allocator (what |
I noticed this in Firefox (where we do build with
-C lto -C opt-level=2
). Essentially any use of an API that ends up calling __rust_realloc generates useless code. A small testcase is:which, with the following
Cargo.toml
config:generates the following assembly:
That's a lot of code, and the most notable in here is that there's a call to
realloc
, two calls toposix_memalign
, one tofree
and one tomalloc
.Now, to understand what's going on, let's write our own copy of the
GlobalAlloc
implementation:(this compiles to the same assembly)
What's going on here is that
layout.align()
is, in our inlined case, a constant for the alignment ofusize
, which is 8 on x86_64, solayout.align() <= MIN_ALIGN
is always true. However, because thenew_size
given torealloc
is notNonZero
(despite the GlobalAlloc documentation specifying the value can never be 0), LLVM doesn't know that the conditionlayout.align() <= new_size
is also always true, so it ends up creating code for bothlibc::realloc
andrealloc_fallback
branches.Changing the condition in
realloc
to forcenew_size == 0
to go throughlibc::realloc
gets rid of the call tofree
and one call toposix_memalign
. Sadly, doing the same withlayout.size() == 0
inalloc
to calllibc::malloc
doesn't get right of the otherposix_memalign
call. I guess the compiler still thinks that the new size computed inRawVec::reserve_internal
can be somewhere betweenlayout.align()
andlayout.size()
, which is actually not possible.Assuming we can somehow get the compiler to get rid of that useless
posix_memalign
, that still leaves us with, essentially, code doingnew_ptr = if ptr { libc::realloc(ptr, new_size) } else { libc::malloc(new_size) }
, which, considering the API guarantees oflibc::realloc
, is a branch and a function call too much, sincenew_ptr = libc::realloc(ptr, new_size)
would work just as well,libc::realloc(ptr::null_mut(), new_size)
being the same aslibc::malloc(new_size)
. Sadly, there's nothing in the Alloc API that would allow to fold this.Cc: @SimonSapin
The text was updated successfully, but these errors were encountered: