2015-05-24 11:07:52 -05:00
|
|
|
// compile-flags: -C no-prepopulate-passes
|
2017-06-25 04:42:55 -05:00
|
|
|
// ignore-tidy-linelength
|
2015-05-24 11:07:52 -05:00
|
|
|
|
2015-09-15 16:22:16 -05:00
|
|
|
#![crate_type = "lib"]
|
2017-06-03 16:54:08 -05:00
|
|
|
#![feature(custom_attribute)]
|
2015-05-24 11:07:52 -05:00
|
|
|
|
|
|
|
pub struct S {
|
2017-10-03 02:45:07 -05:00
|
|
|
_field: [i32; 8],
|
2015-05-24 11:07:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct UnsafeInner {
|
|
|
|
_field: std::cell::UnsafeCell<i16>,
|
|
|
|
}
|
|
|
|
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 13:49:36 -05:00
|
|
|
// CHECK: zeroext i1 @boolean(i1 zeroext %x)
|
2015-05-24 11:07:52 -05:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn boolean(x: bool) -> bool {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
|
2015-05-24 11:07:52 -05:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn readonly_borrow(_: &i32) {
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
|
2015-05-24 11:07:52 -05:00
|
|
|
// static borrow may be captured
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn static_borrow(_: &'static i32) {
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
|
2015-05-24 11:07:52 -05:00
|
|
|
// borrow with named lifetime may be captured
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn named_borrow<'r>(_: &'r i32) {
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %arg0)
|
2015-05-24 11:07:52 -05:00
|
|
|
// unsafe interior means this isn't actually readonly and there may be aliases ...
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn unsafe_borrow(_: &UnsafeInner) {
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @mutable_unsafe_borrow(i16* align 2 dereferenceable(2) %arg0)
|
2015-05-24 11:07:52 -05:00
|
|
|
// ... unless this is a mutable borrow, those never alias
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @mutable_borrow(i32* align 4 dereferenceable(4) %arg0)
|
2015-05-24 11:07:52 -05:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn mutable_borrow(_: &mut i32) {
|
|
|
|
}
|
|
|
|
|
2017-11-19 04:13:24 -06:00
|
|
|
// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32) %arg0)
|
2015-05-24 11:07:52 -05:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn indirect_struct(_: S) {
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %arg0)
|
2015-05-24 11:07:52 -05:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn borrowed_struct(_: &S) {
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: noalias align 4 dereferenceable(4) i32* @_box(i32* noalias align 4 dereferenceable(4) %x)
|
2015-05-24 11:07:52 -05:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn _box(x: Box<i32>) -> Box<i32> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2017-11-19 04:13:24 -06:00
|
|
|
// CHECK: @struct_return(%S* noalias nocapture sret dereferenceable(32))
|
2015-05-24 11:07:52 -05:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn struct_return() -> S {
|
|
|
|
S {
|
2017-10-03 02:45:07 -05:00
|
|
|
_field: [0, 0, 0, 0, 0, 0, 0, 0]
|
2015-05-24 11:07:52 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
// Hack to get the correct size for the length part in slices
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 13:49:36 -05:00
|
|
|
// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
#[no_mangle]
|
2017-10-30 12:18:00 -05:00
|
|
|
pub fn helper(_: usize) {
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1)
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
2017-10-30 12:18:00 -05:00
|
|
|
pub fn slice(_: &[u8]) {
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @mutable_slice([0 x i8]* nonnull align 1 %arg0.0, [[USIZE]] %arg0.1)
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
2017-10-30 12:18:00 -05:00
|
|
|
pub fn mutable_slice(_: &mut [u8]) {
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %arg0.0, [[USIZE]] %arg0.1)
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
// unsafe interior means this isn't actually readonly and there may be aliases ...
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn unsafe_slice(_: &[UnsafeInner]) {
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1)
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
2017-10-30 12:18:00 -05:00
|
|
|
pub fn str(_: &[u8]) {
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @trait_borrow({}* nonnull align 1 %arg0.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %arg0.1)
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
2017-10-30 12:18:00 -05:00
|
|
|
pub fn trait_borrow(_: &Drop) {
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: @trait_box({}* noalias nonnull align 1, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}))
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
#[no_mangle]
|
2017-10-30 12:18:00 -05:00
|
|
|
pub fn trait_box(_: Box<Drop>) {
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: { i8*, i8* } @trait_option(i8* noalias align 1 %x.0, i8* %x.1)
|
2018-03-26 09:26:03 -05:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn trait_option(x: Option<Box<Drop>>) -> Option<Box<Drop>> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2018-12-20 17:30:35 -06:00
|
|
|
// CHECK: { [0 x i16]*, [[USIZE]] } @return_slice([0 x i16]* noalias nonnull readonly align 2 %x.0, [[USIZE]] %x.1)
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
#[no_mangle]
|
2017-10-30 12:18:00 -05:00
|
|
|
pub fn return_slice(x: &[u16]) -> &[u16] {
|
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)
2015-06-18 16:57:40 -05:00
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2018-03-27 09:44:03 -05:00
|
|
|
// CHECK: { i16, i16 } @enum_id_1(i16 %x.0, i16 %x.1)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
Store scalar pair bools as i8 in memory
We represent `bool` as `i1` in a `ScalarPair`, unlike other aggregates,
to optimize IR for checked operators and the like. With this patch, we
still do so when the pair is an immediate value, but we use the `i8`
memory type when the value is loaded or stored as an LLVM aggregate.
So `(bool, bool)` looks like an `{ i1, i1 }` immediate, but `{ i8, i8 }`
in memory. When a pair is a direct function argument, `PassMode::Pair`,
it is still passed using the immediate `i1` type, but as a return value
it will use the `i8` memory type. Also, `bool`-like` enum tags will now
use scalar pairs when possible, where they were previously excluded due
to optimization issues.
2018-06-15 17:47:54 -05:00
|
|
|
// CHECK: { i8, i8 } @enum_id_2(i1 zeroext %x.0, i8 %x.1)
|
2018-03-27 09:44:03 -05:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2015-05-24 11:07:52 -05:00
|
|
|
// CHECK: noalias i8* @allocator()
|
|
|
|
#[no_mangle]
|
|
|
|
#[allocator]
|
|
|
|
pub fn allocator() -> *const i8 {
|
|
|
|
std::ptr::null()
|
|
|
|
}
|