Open krtab opened 4 months ago
Not an excuse, but an explanation: inclusive ranges also track whether their iteration has been exhausted. That is, 100..100
is already exhausted but 100..=100
must yield once and then stop.
Not sure how easy it will be to identify when such tracking can be optimised away.
FWIW, internal iteration does optimize away the inclusive range:
#[no_mangle]
pub fn f() {
(0..=100).for_each(|_| ());
}
#[no_mangle]
pub fn g() {
for _ in 0..100 {
()
}
}
f: # @f
# %bb.0:
ret
# -- End function
.set g, f
This optimizes better. https://rust.godbolt.org/z/sYabYYKn4
Might be worth a try to see if it helps non-empty loop bodies. But TrustedStep
is insufficient to specialize the integer ranges like this, it'd require something more targeted.
#[no_mangle]
pub fn f() {
let r = RangeInclusive { start: 0, end: 100, exhausted: false };
for _ in r {
()
}
}
#[no_mangle]
pub fn g() {
for _ in 0usize..=100 {
()
}
}
struct RangeInclusive {
start: usize,
end: usize,
exhausted: bool
}
impl Iterator for RangeInclusive {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.exhausted || self.start > self.end {
return None
}
let v = self.start;
// == Current impl
// self.exhausted = if v < self.end {
// self.start = unsafe { v.unchecked_add(1) };
// } else {
// self.exhausted = true;
// };
// == alternative
{
self.start = v.wrapping_add(1);
if v >= self.end {
self.exhausted = true;
}
}
Some(v)
}
}
Godbolt: https://rust.godbolt.org/z/7z8n4broM
The reason this is not optimized is probably undef rules. We likely don't see that %iter.sroa.0.06 isn't undef due to the loop and then can't use the range information.
Could be avoided with this transform: https://alive2.llvm.org/ce/z/7XRLAT Which looks like https://github.com/llvm/llvm-project/issues/82414.
with -O gives
Meta
Exists in both 1.77 and nightly.
Backtrace
```
```
@rustbot label +A-codegen +A-LLVM +C-optimization +I-slow +S-has-mcve +I-heavy +T-compiler -needs-triage