Skip to content

Commit 85d0cdf

Browse files
Auto merge of rust-lang#150265 - scottmcm:vec-less-ubchecks, r=jhpratt
Stop emitting UbChecks on every Vec→Slice Spotted this in rust-lang#148766's test changes. It doesn't seem like this ubcheck would catch anything useful; let's see if skipping it helps perf. (After all, this is inside *every* `[]` on a vec, among other things.)
2 parents 3fda0e4 + c48df5d commit 85d0cdf

9 files changed

+317
-805
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,7 +1747,11 @@ impl<T, A: Allocator> Vec<T, A> {
17471747
// * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow-
17481748
// check ensures that it is not possible to mutably alias `self.buf` within the
17491749
// returned lifetime.
1750-
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
1750+
unsafe {
1751+
// normally this would use `slice::from_raw_parts`, but it's
1752+
// instantiated often enough that avoiding the UB check is worth it
1753+
&*core::intrinsics::aggregate_raw_ptr::<*const [T], _, _>(self.as_ptr(), self.len)
1754+
}
17511755
}
17521756

17531757
/// Extracts a mutable slice of the entire vector.
@@ -1779,7 +1783,11 @@ impl<T, A: Allocator> Vec<T, A> {
17791783
// * We only construct references to `self.buf` through `&self` and `&mut self` methods;
17801784
// borrow-check ensures that it is not possible to construct a reference to `self.buf`
17811785
// within the returned lifetime.
1782-
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
1786+
unsafe {
1787+
// normally this would use `slice::from_raw_parts_mut`, but it's
1788+
// instantiated often enough that avoiding the UB check is worth it
1789+
&mut *core::intrinsics::aggregate_raw_ptr::<*mut [T], _, _>(self.as_mut_ptr(), self.len)
1790+
}
17831791
}
17841792

17851793
/// Returns a raw pointer to the vector's buffer, or a dangling raw pointer

library/core/src/slice/cmp.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,10 @@ impl<T, U> const PartialEq<[U]> for [T]
1313
where
1414
T: [const] PartialEq<U>,
1515
{
16+
#[inline]
1617
fn eq(&self, other: &[U]) -> bool {
1718
SlicePartialEq::equal(self, other)
1819
}
19-
20-
fn ne(&self, other: &[U]) -> bool {
21-
SlicePartialEq::not_equal(self, other)
22-
}
2320
}
2421

2522
#[stable(feature = "rust1", since = "1.0.0")]
@@ -99,10 +96,6 @@ impl<T: PartialOrd> PartialOrd for [T] {
9996
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
10097
const trait SlicePartialEq<B> {
10198
fn equal(&self, other: &[B]) -> bool;
102-
103-
fn not_equal(&self, other: &[B]) -> bool {
104-
!self.equal(other)
105-
}
10699
}
107100

108101
// Generic slice equality
@@ -111,6 +104,11 @@ impl<A, B> const SlicePartialEq<B> for [A]
111104
where
112105
A: [const] PartialEq<B>,
113106
{
107+
// It's not worth trying to inline the loops underneath here *in MIR*,
108+
// and preventing it encourages more useful inlining upstream,
109+
// such as in `<str as PartialEq>::eq`.
110+
// The codegen backend can still inline it later if needed.
111+
#[rustc_no_mir_inline]
114112
default fn equal(&self, other: &[B]) -> bool {
115113
if self.len() != other.len() {
116114
return false;
@@ -140,6 +138,16 @@ impl<A, B> const SlicePartialEq<B> for [A]
140138
where
141139
A: [const] BytewiseEq<B>,
142140
{
141+
// This is usually a pretty good backend inlining candidate because the
142+
// intrinsic tends to just be `memcmp`. However, as of 2025-12 letting
143+
// MIR inline this makes reuse worse because it means that, for example,
144+
// `String::eq` doesn't inline, whereas by keeping this from inling all
145+
// the wrappers until the call to this disappear. If the heuristics have
146+
// changed and this is no longer fruitful, though, please do remove it.
147+
// In the mean time, it's fine to not inline it in MIR because the backend
148+
// will still inline it if it things it's important to do so.
149+
#[rustc_no_mir_inline]
150+
#[inline]
143151
fn equal(&self, other: &[B]) -> bool {
144152
if self.len() != other.len() {
145153
return false;

tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
scope 4 {
2727
debug _x => _8;
2828
}
29-
scope 18 (inlined foo) {
29+
scope 19 (inlined foo) {
3030
let mut _27: *const [()];
3131
}
3232
}
33-
scope 16 (inlined slice_from_raw_parts::<()>) {
34-
scope 17 (inlined std::ptr::from_raw_parts::<[()], ()>) {
33+
scope 17 (inlined slice_from_raw_parts::<()>) {
34+
scope 18 (inlined std::ptr::from_raw_parts::<[()], ()>) {
3535
}
3636
}
3737
}
@@ -49,19 +49,21 @@
4949
scope 7 {
5050
let _21: std::ptr::NonNull<[u8]>;
5151
scope 8 {
52-
scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) {
53-
scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) {
54-
scope 13 (inlined NonNull::<[u8]>::cast::<u8>) {
52+
scope 12 (inlined NonNull::<[u8]>::as_mut_ptr) {
53+
scope 13 (inlined NonNull::<[u8]>::as_non_null_ptr) {
54+
scope 14 (inlined NonNull::<[u8]>::cast::<u8>) {
5555
let mut _25: *mut [u8];
56-
scope 14 (inlined NonNull::<[u8]>::as_ptr) {
56+
scope 15 (inlined NonNull::<[u8]>::as_ptr) {
5757
}
5858
}
5959
}
60-
scope 15 (inlined NonNull::<u8>::as_ptr) {
60+
scope 16 (inlined NonNull::<u8>::as_ptr) {
6161
}
6262
}
6363
}
6464
scope 10 (inlined <std::alloc::Global as Allocator>::allocate) {
65+
scope 11 (inlined std::alloc::Global::alloc_impl) {
66+
}
6567
}
6668
}
6769
scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) {
@@ -192,8 +194,8 @@
192194
+ _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }};
193195
StorageDead(_24);
194196
StorageLive(_19);
195-
- _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable];
196-
+ _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable];
197+
- _19 = std::alloc::Global::alloc_impl_runtime(copy _18, const false) -> [return: bb7, unwind unreachable];
198+
+ _19 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable];
197199
}
198200

199201
bb7: {

0 commit comments

Comments
 (0)