Skip to content

slice::Iter + max on array: Regression since Rust 1.65 (LLVM 15) #129583

Open
@seritools

Description

@seritools

Code

I tried this code:

pub fn fna(x: [u8; 1024]) -> u8 {
    x.into_iter().max().unwrap()
}

pub fn fnb(x: [u8; 1024]) -> u8 {
    *x.iter().max().unwrap()
}

Godbolt

I expected to see this happen:

  1. Both functions should optimize away the unwrap
  2. (Bonus) Both functions should inline the respective iterator functions and auto-vectorize

Instead, this happened:

  1. fna has no unwrap in the assembly output, but fnb has.
  2. (Bonus) Both inline their respective iterators (according to the MIR output on the playground). fna auto-vectorizes, but fnb doesn't.

fnb generates a byte-wise max implementation. Interestingly, it keeps some information about the array length around, influencing the codegen. A byte-wise max implementation for [u8; 1024] will need to do 1023 comparisons (since the first value of the array will be the initial max result value), and 1023 is divisible by 3, so the compiler emits a loop that emits a loop that runs 341 times, doing 3 max computations each. If I change the length of the array to 1025, it will do 4 max computations each.

Even though the generated code relies on the number of array entries, it still doesn't elide the Option::unwrap check for the max result. In Rust 1.45-1.64 fnb also generates the 3-byte-at-a-time loop, but does remove the Option::unwrap.

Version it worked on

It most recently worked on: Rust 1.64. (For context: Rust 1.65 added LLVM 15.)

It (initially?) started working in 1.45 (that version added LLVM 10).

Version with regression

Any version since Rust 1.65.


Since I thought this behavior was unexpected, I polled it on mastodon before looking further into it. ATM about half of the respondents thought just like me that both should be optimized (at least the unwrap part):

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.I-slowIssue: Problems and improvements with respect to performance of generated code.P-lowLow priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.llvm-fixed-upstreamIssue expected to be fixed by the next major LLVM upgrade, or backported fixesregression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions