Pass fat pointers in two immediate arguments
This has a number of advantages compared to creating a copy in memory and passing a pointer. The obvious one is that we don't have to put the data into memory but can keep it in registers. Since we're currently passing a pointer anyway (instead of using e.g. a known offset on the stack, which is what the `byval` attribute would achieve), we only use a single additional register for each fat pointer, but save at least two pointers worth of stack in exchange (sometimes more because more than one copy gets eliminated). On archs that pass arguments on the stack, we save a pointer worth of stack even without considering the omitted copies. Additionally, LLVM can optimize the code a lot better, to a large degree due to the fact that lots of copies are gone or can be optimized away. Additionally, we can now emit attributes like nonnull on the data and/or vtable pointers contained in the fat pointer, potentially allowing for even more optimizations. This results in LLVM passes being about 3-7% faster (depending on the crate), and the resulting code is also a few percent smaller, for example: text data filename 5671479 3941461 before/librustc-d8ace771.so 5447663 3905745 after/librustc-d8ace771.so 1944425 2394024 before/libstd-d8ace771.so 1896769 2387610 after/libstd-d8ace771.so I had to remove a call in the backtrace-debuginfo test, because LLVM can now merge the tails of some blocks when optimizations are turned on, which can't correctly preserve line info. Fixes #22924 Cc #22891 (at least for fat pointers the code is good now)
This commit is contained in:
parent
02d74a4852
commit
f777562eab
15 changed files with 229 additions and 119 deletions
|
@ -87,6 +87,53 @@ pub fn struct_return() -> S {
|
|||
}
|
||||
}
|
||||
|
||||
// Hack to get the correct size for the length part in slices
|
||||
// CHECK: @helper([[USIZE:i[0-9]+]])
|
||||
#[no_mangle]
|
||||
fn helper(_: usize) {
|
||||
}
|
||||
|
||||
// CHECK: @slice(i8* noalias nonnull readonly, [[USIZE]])
|
||||
// FIXME #25759 This should also have `nocapture`
|
||||
#[no_mangle]
|
||||
fn slice(_: &[u8]) {
|
||||
}
|
||||
|
||||
// CHECK: @mutable_slice(i8* noalias nonnull, [[USIZE]])
|
||||
// FIXME #25759 This should also have `nocapture`
|
||||
#[no_mangle]
|
||||
fn mutable_slice(_: &mut [u8]) {
|
||||
}
|
||||
|
||||
// CHECK: @unsafe_slice(%UnsafeInner* nonnull, [[USIZE]])
|
||||
// unsafe interior means this isn't actually readonly and there may be aliases ...
|
||||
#[no_mangle]
|
||||
pub fn unsafe_slice(_: &[UnsafeInner]) {
|
||||
}
|
||||
|
||||
// CHECK: @str(i8* noalias nonnull readonly, [[USIZE]])
|
||||
// FIXME #25759 This should also have `nocapture`
|
||||
#[no_mangle]
|
||||
fn str(_: &[u8]) {
|
||||
}
|
||||
|
||||
// CHECK: @trait_borrow(i8* nonnull, void (i8*)** nonnull)
|
||||
// FIXME #25759 This should also have `nocapture`
|
||||
#[no_mangle]
|
||||
fn trait_borrow(_: &Drop) {
|
||||
}
|
||||
|
||||
// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** nonnull)
|
||||
#[no_mangle]
|
||||
fn trait_box(_: Box<Drop>) {
|
||||
}
|
||||
|
||||
// CHECK: { i16*, [[USIZE]] } @return_slice(i16* noalias nonnull readonly, [[USIZE]])
|
||||
#[no_mangle]
|
||||
fn return_slice(x: &[u16]) -> &[u16] {
|
||||
x
|
||||
}
|
||||
|
||||
// CHECK: noalias i8* @allocator()
|
||||
#[no_mangle]
|
||||
#[allocator]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue