`slice.iter().take_while(f).count()` produces suboptimal assembly code
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code:
(1)
pub fn trim_starting_odd_elems_while(slice: &[u32]) -> (usize, &[u32]) {
let mut start_idx = 0;
while start_idx < slice.len() {
if slice[start_idx] % 2 != 0 {
break;
}
start_idx += 1;
}
(start_idx, &slice[start_idx..])
}
pub fn trim_starting_odd_elems_iter(slice: &[u32]) -> (usize, &[u32]) {
let start_idx = slice
.iter()
.position(|f| *f % 2 != 0)
.unwrap_or(slice.len());
(start_idx, &slice[start_idx..])
}
pub fn trim_starting_odd_elems_iter_count(slice: &[u32]) -> (usize, &[u32]) {
let start_idx = slice
.iter()
.take_while(|f| *f % 2 != 0)
.count();
(start_idx, &slice[start_idx..])
}
(2)
pub fn trim_ending_odd_elems_while(slice: &[u32]) -> (usize, &[u32]) {
let mut end_idx = slice.len();
while end_idx > 0 {
if slice[end_idx - 1] % 2 != 0 {
break;
}
end_idx -= 1;
}
(end_idx, &slice[..end_idx])
}
pub fn trim_ending_odd_elems_iter(slice: &[u32]) -> (usize, &[u32]) {
let end_idx = slice
.iter()
.rposition(|f| *f % 2 != 0)
.map_or(0, |i| i + 1);
(end_idx, &slice[..end_idx])
}
pub fn trim_ending_odd_elems_iter_count(slice: &[u32]) -> (usize, &[u32]) {
let end_skip = slice
.iter()
.rev()
.take_while(|f| *f % 2 != 0)
.count();
let end_idx = slice.len() - end_skip;
(end_idx, &slice[..end_idx])
}
I expected to see this happen: All three of the functions in (1) or (2) should produce the same assembly.
Instead, this happened: In (1), trim_starting_odd_elems_iter produces the shortest (and probably fastest) assembly. In (2), trim_ending_odd_elems_while produces the shortest assembly. (See playground link)
Meta
rustc --version --verbose:
rustc 1.82.0-nightly (cefe1dcef 2024-07-22)
binary: rustc
commit-hash: cefe1dcef0e21f4d0c8ea856ad61c1936dfb7913
commit-date: 2024-07-22
host: x86_64-unknown-linux-gnu
release: 1.82.0-nightly
LLVM version: 18.1.7
Also happens on rustc 1.79.0.
Backtrace: N/A
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked Rust Playground and reproduce the release-mode assembly for the three functions in each example using the reported stable and nightly versions. Compare the iterator forms with the equivalent while loops, then trace the relevant compiler optimization or iterator-lowering behavior. Done means the affected forms produce equivalent, improved assembly or the limitation is documented with a focused regression test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100