Skip to content

slice.iter().take_while(f).count() produces suboptimal assembly code #128208

Open
@bluebear94

Description

@bluebear94

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-heavyIssue: Problems and improvements with respect to binary size of generated code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions