Skip to content

Commit ebee2ff

Browse files
committed
use indexed loop instead of ptr bumping
this seems to produce less IR
1 parent e7ec667 commit ebee2ff

File tree

1 file changed

+20
-10
lines changed

1 file changed

+20
-10
lines changed

core/src/slice/iter/macros.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,33 @@ macro_rules! iterator {
192192
}
193193

194194
#[inline]
195-
fn fold<B, F>(mut self, init: B, mut f: F) -> B
195+
fn fold<B, F>(self, init: B, mut f: F) -> B
196196
where
197197
F: FnMut(B, Self::Item) -> B,
198198
{
199-
// Handling the 0-len case explicitly and then using a do-while style loop
200-
// helps the optimizer. See issue #106288
199+
// this implementation consists of the following optimizations compared to the
200+
// default implementation:
201+
// - do-while loop, as is llvm's preferred loop shape,
202+
// see https://releases.llvm.org/16.0.0/docs/LoopTerminology.html#more-canonical-loops
203+
// - bumps an index instead of a pointer since the latter case inhibits
204+
// some optimizations, see #111603
205+
// - avoids Option wrapping/matching
201206
if is_empty!(self) {
202207
return init;
203208
}
204209
let mut acc = init;
205-
// SAFETY: The 0-len case was handled above so one loop iteration is guaranteed.
206-
unsafe {
207-
loop {
208-
acc = f(acc, next_unchecked!(self));
209-
if is_empty!(self) {
210-
break;
211-
}
210+
let mut i = 0;
211+
let len = len!(self);
212+
loop {
213+
// SAFETY: the loop iterates `i in 0..len`, which always is in bounds of
214+
// the slice allocation
215+
acc = f(acc, unsafe { & $( $mut_ )? *self.ptr.add(i).as_ptr() });
216+
// SAFETY: `i` can't overflow since it'll only reach usize::MAX if the
217+
// slice had that length, in which case we'll break out of the loop
218+
// after the increment
219+
i = unsafe { i.unchecked_add(1) };
220+
if i == len {
221+
break;
212222
}
213223
}
214224
acc

0 commit comments

Comments
 (0)