2021-03-19 21:49:51 +00:00
|
|
|
// compile-flags: -O -C no-prepopulate-passes
|
2015-05-24 16:07:52 +00:00
|
|
|
|
2015-09-15 21:22:16 +00:00
|
|
|
#![crate_type = "lib"]
|
2023-02-10 23:54:05 +00:00
|
|
|
#![feature(dyn_star)]
|
2015-05-24 16:07:52 +00:00
|
|
|
|
2022-02-07 02:09:21 +00:00
|
|
|
use std::mem::MaybeUninit;
|
2022-02-12 06:38:24 +00:00
|
|
|
use std::num::NonZeroU64;
|
2022-06-21 03:51:15 +00:00
|
|
|
use std::marker::PhantomPinned;
|
2022-12-30 20:11:30 +00:00
|
|
|
use std::ptr::NonNull;
|
2022-02-07 02:09:21 +00:00
|
|
|
|
2015-05-24 16:07:52 +00:00
|
|
|
pub struct S {
|
2017-10-03 07:45:07 +00:00
|
|
|
_field: [i32; 8],
|
2015-05-24 16:07:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct UnsafeInner {
|
|
|
|
_field: std::cell::UnsafeCell<i16>,
|
|
|
|
}
|
|
|
|
|
2022-06-21 03:51:15 +00:00
|
|
|
pub struct NotUnpin {
|
|
|
|
_field: i32,
|
|
|
|
_marker: PhantomPinned,
|
|
|
|
}
|
|
|
|
|
2022-02-12 06:38:24 +00:00
|
|
|
pub enum MyBool {
|
|
|
|
True,
|
|
|
|
False,
|
|
|
|
}
|
|
|
|
|
2022-02-05 06:00:37 +00:00
|
|
|
// CHECK: noundef zeroext i1 @boolean(i1 noundef zeroext %x)
|
2015-05-24 16:07:52 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn boolean(x: bool) -> bool {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-02-07 02:09:21 +00:00
|
|
|
// CHECK: i8 @maybeuninit_boolean(i8 %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-02-12 06:38:24 +00:00
|
|
|
// CHECK: noundef zeroext i1 @enum_bool(i1 noundef zeroext %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn enum_bool(x: MyBool) -> MyBool {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: i8 @maybeuninit_enum_bool(i8 %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: noundef i32 @char(i32 noundef %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn char(x: char) -> char {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: i32 @maybeuninit_char(i32 %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: noundef i64 @int(i64 noundef %x)
|
2022-02-12 06:38:24 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn int(x: u64) -> u64 {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: noundef i64 @nonzero_int(i64 noundef %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn nonzero_int(x: NonZeroU64) -> NonZeroU64 {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: noundef i64 @option_nonzero_int(i64 noundef %x)
|
2022-02-12 06:38:24 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @readonly_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
|
2015-05-24 16:07:52 +00:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn readonly_borrow(_: &i32) {
|
|
|
|
}
|
|
|
|
|
2022-12-27 11:46:08 +00:00
|
|
|
// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @readonly_borrow_ret()
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn readonly_borrow_ret() -> &'static i32 {
|
|
|
|
loop {}
|
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @static_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
|
2015-05-24 16:07:52 +00:00
|
|
|
// static borrow may be captured
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn static_borrow(_: &'static i32) {
|
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @named_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
|
2015-05-24 16:07:52 +00:00
|
|
|
// borrow with named lifetime may be captured
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn named_borrow<'r>(_: &'r i32) {
|
|
|
|
}
|
|
|
|
|
2022-06-21 03:51:15 +00:00
|
|
|
// CHECK: @unsafe_borrow({{i16\*|ptr}} noundef nonnull align 2 %_1)
|
2015-05-24 16:07:52 +00:00
|
|
|
// unsafe interior means this isn't actually readonly and there may be aliases ...
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn unsafe_borrow(_: &UnsafeInner) {
|
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @mutable_unsafe_borrow({{i16\*|ptr}} noalias noundef align 2 dereferenceable(2) %_1)
|
2015-05-24 16:07:52 +00:00
|
|
|
// ... unless this is a mutable borrow, those never alias
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
|
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @mutable_borrow({{i32\*|ptr}} noalias noundef align 4 dereferenceable(4) %_1)
|
2015-05-24 16:07:52 +00:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn mutable_borrow(_: &mut i32) {
|
|
|
|
}
|
|
|
|
|
2022-12-27 11:46:08 +00:00
|
|
|
// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @mutable_borrow_ret()
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn mutable_borrow_ret() -> &'static mut i32 {
|
|
|
|
loop {}
|
|
|
|
}
|
|
|
|
|
2022-06-21 03:51:15 +00:00
|
|
|
#[no_mangle]
|
2022-12-27 11:46:08 +00:00
|
|
|
// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef nonnull align 4 %_1)
|
2022-06-21 03:51:15 +00:00
|
|
|
// This one is *not* `noalias` because it might be self-referential.
|
2022-12-27 11:46:08 +00:00
|
|
|
// It is also not `dereferenceable` due to
|
|
|
|
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
|
2022-06-21 03:51:15 +00:00
|
|
|
pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: @notunpin_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
|
|
|
|
// But `&NotUnpin` behaves perfectly normal.
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn notunpin_borrow(_: &NotUnpin) {
|
|
|
|
}
|
|
|
|
|
Introduce deduced parameter attributes, and use them for deducing `readonly` on
indirect immutable freeze by-value function parameters.
Right now, `rustc` only examines function signatures and the platform ABI when
determining the LLVM attributes to apply to parameters. This results in missed
optimizations, because there are some attributes that can be determined via
analysis of the MIR making up the function body. In particular, `readonly`
could be applied to most indirectly-passed by-value function arguments
(specifically, those that are freeze and are observed not to be mutated), but
it currently is not.
This patch introduces the machinery that allows `rustc` to determine those
attributes. It consists of a query, `deduced_param_attrs`, that, when
evaluated, analyzes the MIR of the function to determine supplementary
attributes. The results of this query for each function are written into the
crate metadata so that the deduced parameter attributes can be applied to
cross-crate functions. In this patch, we simply check the parameter for
mutations to determine whether the `readonly` attribute should be applied to
parameters that are indirect immutable freeze by-value. More attributes could
conceivably be deduced in the future: `nocapture` and `noalias` come to mind.
Adding `readonly` to indirect function parameters where applicable enables some
potential optimizations in LLVM that are discussed in [issue 103103] and [PR
103070] around avoiding stack-to-stack memory copies that appear in functions
like `core::fmt::Write::write_fmt` and `core::panicking::assert_failed`. These
functions pass a large structure unchanged by value to a subfunction that also
doesn't mutate it. Since the structure in this case is passed as an indirect
parameter, it's a pointer from LLVM's perspective. As a result, the
intermediate copy of the structure that our codegen emits could be optimized
away by LLVM's MemCpyOptimizer if it knew that the pointer is `readonly
nocapture noalias` in both the caller and callee. We already pass `nocapture
noalias`, but we're missing `readonly`, as we can't determine whether a
by-value parameter is mutated by examining the signature in Rust. I didn't have
much success with having LLVM infer the `readonly` attribute, even with fat
LTO; it seems that deducing it at the MIR level is necessary.
No large benefits should be expected from this optimization *now*; LLVM needs
some changes (discussed in [PR 103070]) to more aggressively use the `noalias
nocapture readonly` combination in its alias analysis. I have some LLVM patches
for these optimizations and have had them looked over. With all the patches
applied locally, I enabled LLVM to remove all the `memcpy`s from the following
code:
```rust
fn main() {
println!("Hello {}", 3);
}
```
which is a significant codegen improvement over the status quo. I expect that
if this optimization kicks in in multiple places even for such a simple
program, then it will apply to Rust code all over the place.
[issue 103103]: https://github.com/rust-lang/rust/issues/103103
[PR 103070]: https://github.com/rust-lang/rust/pull/103070
2022-10-18 02:42:15 +00:00
|
|
|
// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef readonly dereferenceable(32) %_1)
|
2015-05-24 16:07:52 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn indirect_struct(_: S) {
|
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @borrowed_struct({{%S\*|ptr}} noalias noundef readonly align 4 dereferenceable(32) %_1)
|
2015-05-24 16:07:52 +00:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn borrowed_struct(_: &S) {
|
|
|
|
}
|
|
|
|
|
2022-12-30 20:11:30 +00:00
|
|
|
// CHECK: @option_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable_or_null(4) %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn option_borrow(x: Option<&i32>) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: @option_borrow_mut({{i32\*|ptr}} noalias noundef align 4 dereferenceable_or_null(4) %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn option_borrow_mut(x: Option<&mut i32>) {
|
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: @raw_struct({{%S\*|ptr}} noundef %_1)
|
2022-02-05 06:00:37 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn raw_struct(_: *const S) {
|
|
|
|
}
|
|
|
|
|
2022-12-30 20:11:30 +00:00
|
|
|
// CHECK: @raw_option_nonnull_struct({{i32\*|ptr}} noundef %_1)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn raw_option_nonnull_struct(_: Option<NonNull<S>>) {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-22 21:04:22 +00:00
|
|
|
// `Box` can get deallocated during execution of the function, so it should
|
|
|
|
// not get `dereferenceable`.
|
2023-01-02 14:11:19 +00:00
|
|
|
// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
|
2015-05-24 16:07:52 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn _box(x: Box<i32>) -> Box<i32> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2023-01-02 13:09:01 +00:00
|
|
|
// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @notunpin_box({{i32\*|ptr}} noundef nonnull align 4 %x)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %0)?}})
|
2015-05-24 16:07:52 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn struct_return() -> S {
|
|
|
|
S {
|
2017-10-03 07:45:07 +00:00
|
|
|
_field: [0, 0, 0, 0, 0, 0, 0, 0]
|
2015-05-24 16:07:52 +00: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 21:57:40 +00:00
|
|
|
// Hack to get the correct size for the length part in slices
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_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 21:57:40 +00:00
|
|
|
#[no_mangle]
|
2017-10-30 17:18:00 +00: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 21:57:40 +00:00
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: @slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.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 21:57:40 +00:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
2017-10-30 17:18:00 +00: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 21:57:40 +00:00
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: @mutable_slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.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 21:57:40 +00:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
2017-10-30 17:18:00 +00: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 21:57:40 +00:00
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: @unsafe_slice({{\[0 x i16\]\*|ptr}} noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.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 21:57:40 +00:00
|
|
|
// unsafe interior means this isn't actually readonly and there may be aliases ...
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn unsafe_slice(_: &[UnsafeInner]) {
|
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: @raw_slice({{\[0 x i8\]\*|ptr}} noundef %_1.0, [[USIZE]] noundef %_1.1)
|
2022-02-05 06:00:37 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn raw_slice(_: *const [u8]) {
|
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: @str({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.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 21:57:40 +00:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
2017-10-30 17:18:00 +00: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 21:57:40 +00:00
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @trait_borrow({{\{\}\*|ptr}} noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.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 21:57:40 +00:00
|
|
|
// FIXME #25759 This should also have `nocapture`
|
|
|
|
#[no_mangle]
|
2022-12-30 14:55:05 +00:00
|
|
|
pub fn trait_borrow(_: &dyn 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 21:57:40 +00:00
|
|
|
}
|
|
|
|
|
2022-12-30 20:11:30 +00:00
|
|
|
// CHECK: @option_trait_borrow({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn option_trait_borrow(x: Option<&dyn Drop>) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: @option_trait_borrow_mut({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
|
|
|
|
#[no_mangle]
|
|
|
|
pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {
|
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: @trait_raw({{\{\}\*|ptr}} noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
|
2022-02-05 06:00:37 +00:00
|
|
|
#[no_mangle]
|
2022-12-30 14:55:05 +00:00
|
|
|
pub fn trait_raw(_: *const dyn Drop) {
|
2022-02-05 06:00:37 +00:00
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: @trait_box({{\{\}\*|ptr}} noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %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 21:57:40 +00:00
|
|
|
#[no_mangle]
|
2023-01-02 13:09:01 +00:00
|
|
|
pub fn trait_box(_: Box<dyn Drop + Unpin>) {
|
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 21:57:40 +00:00
|
|
|
}
|
|
|
|
|
2022-02-21 10:21:23 +00:00
|
|
|
// CHECK: { {{i8\*|ptr}}, {{i8\*|ptr}} } @trait_option({{i8\*|ptr}} noalias noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
|
2018-03-26 14:26:03 +00:00
|
|
|
#[no_mangle]
|
2023-01-02 13:09:01 +00:00
|
|
|
pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + Unpin>> {
|
2018-03-26 14:26:03 +00:00
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-12-30 14:55:05 +00:00
|
|
|
// CHECK: { {{\[0 x i16\]\*|ptr}}, [[USIZE]] } @return_slice({{\[0 x i16\]\*|ptr}} noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %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 21:57:40 +00:00
|
|
|
#[no_mangle]
|
2017-10-30 17:18:00 +00: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 21:57:40 +00:00
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-02-12 06:38:24 +00:00
|
|
|
// CHECK: { i16, i16 } @enum_id_1(i16 noundef %x.0, i16 %x.1)
|
2018-03-27 14:44:03 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
2022-02-05 06:00:37 +00:00
|
|
|
// CHECK: { i8, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1)
|
2018-03-27 14:44:03 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
|
|
|
|
x
|
|
|
|
}
|
2023-02-10 23:54:05 +00:00
|
|
|
|
2023-02-15 03:42:45 +00:00
|
|
|
// CHECK: { {{\{\}\*|ptr}}, {{.+}} } @dyn_star({{\{\}\*|ptr}} noundef %x.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %x.1)
|
|
|
|
// Expect an ABI something like `{ {}*, [3 x i64]* }`, but that's hard to match on generically,
|
|
|
|
// so do like the `trait_box` test and just match on `{{.+}}` for the vtable.
|
2023-02-10 23:54:05 +00:00
|
|
|
#[no_mangle]
|
|
|
|
pub fn dyn_star(x: dyn* Drop) -> dyn* Drop {
|
|
|
|
x
|
|
|
|
}
|