Skip to content

Commit 85deb4d

Browse files
committed
Simplify slice::Iter::next enough that it inlines
1 parent be1489f commit 85deb4d

8 files changed

+771
-150
lines changed

library/core/src/slice/iter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::iter::{
1111
use crate::marker::PhantomData;
1212
use crate::mem::{self, SizedTypeProperties};
1313
use crate::num::NonZero;
14-
use crate::ptr::{NonNull, without_provenance, without_provenance_mut};
14+
use crate::ptr::{NonNull, null, without_provenance, without_provenance_mut};
1515
use crate::{cmp, fmt};
1616

1717
#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]

library/core/src/slice/iter/macros.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -154,16 +154,26 @@ macro_rules! iterator {
154154

155155
#[inline]
156156
fn next(&mut self) -> Option<$elem> {
157-
// could be implemented with slices, but this avoids bounds checks
157+
// intentionally not using the helpers because this is
158+
// one of the most mono'd things in the library.
158159

159-
// SAFETY: The call to `next_unchecked` is
160-
// safe since we check if the iterator is empty first.
160+
let ptr = self.ptr;
161+
let end_or_len = self.end_or_len;
162+
// SAFETY: Type invariants.
161163
unsafe {
162-
if is_empty!(self) {
163-
None
164+
if T::IS_ZST {
165+
let byte_end = end_or_len as *const u8;
166+
if byte_end == null() {
167+
return None;
168+
}
169+
self.end_or_len = byte_end.wrapping_sub(1) as _;
164170
} else {
165-
Some(self.next_unchecked())
171+
if ptr == crate::intrinsics::transmute::<*const T, NonNull<T>>(end_or_len) {
172+
return None;
173+
}
174+
self.ptr = ptr.add(1);
166175
}
176+
crate::intrinsics::transmute::<NonNull<T>, Option<$elem>>(ptr)
167177
}
168178
}
169179

tests/codegen/slice-iter-nonnull.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
// CHECK-LABEL: @slice_iter_next(
1515
#[no_mangle]
1616
pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> {
17-
// CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}}
18-
// CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
17+
// CHECK: %[[START:.+]] = load ptr, ptr %it,
1918
// CHECK-SAME: !nonnull
2019
// CHECK-SAME: !noundef
21-
// CHECK: %[[START:.+]] = load ptr, ptr %it,
20+
// CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}}
21+
// CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
2222
// CHECK-SAME: !nonnull
2323
// CHECK-SAME: !noundef
2424
// CHECK: icmp eq ptr %[[START]], %[[END]]

tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir

+189-66
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,30 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
44
debug slice => _1;
55
debug f => _2;
66
let mut _0: ();
7-
let mut _11: std::slice::Iter<'_, T>;
8-
let mut _12: std::iter::Enumerate<std::slice::Iter<'_, T>>;
9-
let mut _13: std::iter::Enumerate<std::slice::Iter<'_, T>>;
10-
let mut _21: std::option::Option<(usize, &T)>;
11-
let mut _24: &impl Fn(usize, &T);
12-
let mut _25: (usize, &T);
13-
let _26: ();
7+
let mut _11: std::ptr::NonNull<T>;
8+
let mut _12: *const T;
9+
let mut _13: usize;
10+
let mut _33: std::option::Option<(usize, &T)>;
11+
let mut _36: &impl Fn(usize, &T);
12+
let mut _37: (usize, &T);
13+
let _38: ();
1414
scope 1 {
15-
debug iter => _13;
16-
let _22: usize;
17-
let _23: &T;
15+
debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11;
16+
debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).1: *const T) => _12;
17+
debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>;
18+
debug ((iter: Enumerate<std::slice::Iter<'_, T>>).1: usize) => _13;
19+
let _34: usize;
20+
let _35: &T;
1821
scope 2 {
19-
debug i => _22;
20-
debug x => _23;
22+
debug i => _34;
23+
debug x => _35;
2124
}
2225
scope 19 (inlined <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next) {
23-
let mut _14: &mut std::slice::Iter<'_, T>;
24-
let mut _15: std::option::Option<&T>;
25-
let mut _19: (usize, bool);
26-
let mut _20: (usize, &T);
26+
let mut _27: std::option::Option<&T>;
27+
let mut _31: (usize, bool);
28+
let mut _32: (usize, &T);
2729
scope 20 {
28-
let _18: usize;
30+
let _30: usize;
2931
scope 25 {
3032
}
3133
}
@@ -40,11 +42,58 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
4042
}
4143
}
4244
scope 26 (inlined <Option<&T> as Try>::branch) {
43-
let mut _16: isize;
44-
let _17: &T;
45+
let mut _28: isize;
46+
let _29: &T;
4547
scope 27 {
4648
}
4749
}
50+
scope 29 (inlined <std::slice::Iter<'_, T> as Iterator>::next) {
51+
let _14: std::ptr::NonNull<T>;
52+
let _16: std::ptr::NonNull<T>;
53+
let mut _19: bool;
54+
let mut _22: std::ptr::NonNull<T>;
55+
let mut _24: bool;
56+
let mut _25: *const u8;
57+
let mut _26: *const T;
58+
scope 30 {
59+
let _15: *const T;
60+
scope 31 {
61+
let _23: *const u8;
62+
scope 32 {
63+
scope 33 (inlined null::<u8>) {
64+
scope 34 (inlined without_provenance::<()>) {
65+
scope 35 (inlined without_provenance_mut::<()>) {
66+
}
67+
}
68+
scope 36 (inlined std::ptr::from_raw_parts::<u8, ()>) {
69+
}
70+
}
71+
scope 37 (inlined std::ptr::const_ptr::<impl *const u8>::wrapping_sub) {
72+
scope 38 (inlined core::num::<impl isize>::wrapping_neg) {
73+
scope 39 (inlined core::num::<impl isize>::wrapping_sub) {
74+
}
75+
}
76+
scope 40 (inlined std::ptr::const_ptr::<impl *const u8>::wrapping_offset) {
77+
}
78+
}
79+
}
80+
scope 41 (inlined <NonNull<T> as PartialEq>::eq) {
81+
let mut _17: *mut T;
82+
let mut _18: *mut T;
83+
scope 42 (inlined NonNull::<T>::as_ptr) {
84+
}
85+
scope 43 (inlined NonNull::<T>::as_ptr) {
86+
}
87+
}
88+
scope 44 (inlined NonNull::<T>::add) {
89+
let mut _20: *const T;
90+
let mut _21: *const T;
91+
scope 45 (inlined NonNull::<T>::as_ptr) {
92+
}
93+
}
94+
}
95+
}
96+
}
4897
}
4998
}
5099
scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -89,9 +138,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
89138
}
90139

91140
bb0: {
92-
StorageLive(_11);
93141
StorageLive(_3);
94-
StorageLive(_6);
95142
StorageLive(_4);
96143
_3 = PtrMetadata(copy _1);
97144
_4 = &raw const (*_1);
@@ -120,86 +167,162 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
120167
}
121168

122169
bb3: {
123-
StorageLive(_10);
124170
_10 = copy _9;
125-
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
126-
StorageDead(_10);
127171
StorageDead(_9);
128172
StorageDead(_4);
129-
StorageDead(_6);
130173
StorageDead(_3);
131-
_12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize };
132-
StorageDead(_11);
174+
StorageLive(_11);
175+
StorageLive(_12);
133176
StorageLive(_13);
134-
_13 = copy _12;
177+
_11 = copy _6;
178+
_12 = copy _10;
179+
_13 = const 0_usize;
135180
goto -> bb4;
136181
}
137182

138183
bb4: {
139-
StorageLive(_21);
140-
StorageLive(_18);
141-
StorageLive(_19);
142-
StorageLive(_15);
184+
StorageLive(_33);
185+
StorageLive(_30);
186+
StorageLive(_31);
187+
StorageLive(_27);
143188
StorageLive(_14);
144-
_14 = &mut (_13.0: std::slice::Iter<'_, T>);
145-
_15 = <std::slice::Iter<'_, T> as Iterator>::next(move _14) -> [return: bb5, unwind unreachable];
189+
StorageLive(_15);
190+
StorageLive(_23);
191+
StorageLive(_16);
192+
_14 = copy _11;
193+
_15 = copy _12;
194+
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8];
146195
}
147196

148197
bb5: {
149-
StorageDead(_14);
150-
StorageLive(_16);
151-
_16 = discriminant(_15);
152-
switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb11];
198+
StorageLive(_19);
199+
_16 = copy _15 as std::ptr::NonNull<T> (Transmute);
200+
StorageLive(_17);
201+
_17 = copy _14 as *mut T (Transmute);
202+
StorageLive(_18);
203+
_18 = copy _16 as *mut T (Transmute);
204+
_19 = Eq(move _17, move _18);
205+
StorageDead(_18);
206+
StorageDead(_17);
207+
switchInt(move _19) -> [0: bb6, otherwise: bb7];
153208
}
154209

155210
bb6: {
156-
StorageDead(_16);
157-
StorageDead(_15);
158211
StorageDead(_19);
159-
StorageDead(_18);
212+
StorageLive(_22);
213+
StorageLive(_21);
214+
StorageLive(_20);
215+
_20 = copy _14 as *const T (Transmute);
216+
_21 = Offset(move _20, const 1_usize);
217+
StorageDead(_20);
218+
_22 = NonNull::<T> { pointer: move _21 };
160219
StorageDead(_21);
161-
StorageDead(_13);
162-
drop(_2) -> [return: bb7, unwind unreachable];
220+
_11 = move _22;
221+
StorageDead(_22);
222+
goto -> bb11;
163223
}
164224

165225
bb7: {
166-
return;
226+
StorageDead(_19);
227+
StorageDead(_16);
228+
StorageDead(_23);
229+
StorageDead(_15);
230+
StorageDead(_14);
231+
StorageLive(_28);
232+
goto -> bb17;
167233
}
168234

169235
bb8: {
170-
_17 = move ((_15 as Some).0: &T);
171-
StorageDead(_16);
172-
StorageDead(_15);
173-
_18 = copy (_13.1: usize);
174-
_19 = AddWithOverflow(copy (_13.1: usize), const 1_usize);
175-
assert(!move (_19.1: bool), "attempt to compute `{} + {}`, which would overflow", copy (_13.1: usize), const 1_usize) -> [success: bb9, unwind unreachable];
236+
_23 = copy _15 as *const u8 (PtrToPtr);
237+
StorageLive(_24);
238+
_24 = Eq(copy _23, const {0x0 as *const u8});
239+
switchInt(move _24) -> [0: bb9, otherwise: bb16];
176240
}
177241

178242
bb9: {
179-
(_13.1: usize) = move (_19.0: usize);
180-
StorageLive(_20);
181-
_20 = (copy _18, copy _17);
182-
_21 = Option::<(usize, &T)>::Some(move _20);
183-
StorageDead(_20);
184-
StorageDead(_19);
185-
StorageDead(_18);
186-
_22 = copy (((_21 as Some).0: (usize, &T)).0: usize);
187-
_23 = copy (((_21 as Some).0: (usize, &T)).1: &T);
188-
StorageLive(_24);
189-
_24 = &_2;
243+
StorageDead(_24);
190244
StorageLive(_25);
191-
_25 = (copy _22, copy _23);
192-
_26 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _24, move _25) -> [return: bb10, unwind unreachable];
245+
_25 = arith_offset::<u8>(move _23, const -1_isize) -> [return: bb10, unwind unreachable];
193246
}
194247

195248
bb10: {
249+
_26 = move _25 as *const T (PtrToPtr);
196250
StorageDead(_25);
197-
StorageDead(_24);
198-
StorageDead(_21);
199-
goto -> bb4;
251+
_12 = copy _26;
252+
goto -> bb11;
200253
}
201254

202255
bb11: {
256+
_27 = copy _14 as std::option::Option<&T> (Transmute);
257+
StorageDead(_16);
258+
StorageDead(_23);
259+
StorageDead(_15);
260+
StorageDead(_14);
261+
StorageLive(_28);
262+
_28 = discriminant(_27);
263+
switchInt(move _28) -> [0: bb17, 1: bb12, otherwise: bb15];
264+
}
265+
266+
bb12: {
267+
_29 = move ((_27 as Some).0: &T);
268+
StorageDead(_28);
269+
StorageDead(_27);
270+
_30 = copy _13;
271+
_31 = AddWithOverflow(copy _13, const 1_usize);
272+
assert(!move (_31.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _13, const 1_usize) -> [success: bb13, unwind unreachable];
273+
}
274+
275+
bb13: {
276+
_13 = move (_31.0: usize);
277+
StorageLive(_32);
278+
_32 = (copy _30, copy _29);
279+
_33 = Option::<(usize, &T)>::Some(move _32);
280+
StorageDead(_32);
281+
StorageDead(_31);
282+
StorageDead(_30);
283+
_34 = copy (((_33 as Some).0: (usize, &T)).0: usize);
284+
_35 = copy (((_33 as Some).0: (usize, &T)).1: &T);
285+
StorageLive(_36);
286+
_36 = &_2;
287+
StorageLive(_37);
288+
_37 = (copy _34, copy _35);
289+
_38 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _36, move _37) -> [return: bb14, unwind unreachable];
290+
}
291+
292+
bb14: {
293+
StorageDead(_37);
294+
StorageDead(_36);
295+
StorageDead(_33);
296+
goto -> bb4;
297+
}
298+
299+
bb15: {
203300
unreachable;
204301
}
302+
303+
bb16: {
304+
StorageDead(_24);
305+
StorageDead(_16);
306+
StorageDead(_23);
307+
StorageDead(_15);
308+
StorageDead(_14);
309+
StorageLive(_28);
310+
goto -> bb17;
311+
}
312+
313+
bb17: {
314+
StorageDead(_28);
315+
StorageDead(_27);
316+
StorageDead(_31);
317+
StorageDead(_30);
318+
StorageDead(_33);
319+
StorageDead(_11);
320+
StorageDead(_12);
321+
StorageDead(_13);
322+
drop(_2) -> [return: bb18, unwind unreachable];
323+
}
324+
325+
bb18: {
326+
return;
327+
}
205328
}

0 commit comments

Comments
 (0)