Change:
I tried this code: expected to see this happen: Instead, this happened: There are two unnecessary instructions: It most recently worked on: Rust 1.63, Rust beta : modify labels: +regression-from-stable-to-nightly -regression-untriaged
Related (maybe):
The "canonical" code produces identical (and, since it has early exit, much more performant in most cases) assemblies between versions.
But constant-time functions can not early exit. The "fold bool" variant should also be optimized when compiled with nighly. So I think it's regression.
Upstream issue:
Aside: I think our labels here are a bit too general; while the text for "regression-from-stable-to-nightly" label itself says "Performance or correctness regression from stable to nightly", I think it should probably be revised to be restricted to "correctness or severe performance regression ..." label: -regression-from-stable-to-nightly
I'm putting back the label for now; I want to get more consensus amongst the team about what the labels should be used for and what they denote (and how to get a narrower view when one wants to filter out cases like this) label: +regression-from-stable-to-nightly
Fixed upstream and will be pulled in with the next LLVM major version upgrade. I'm downgrading the priority as there's no point in revisiting this in triage until that time.
Fixed by the LLVM 16 upgrade.

Discussion:
<ins> // compile-flags: -O // min-llvm-version: 16 #![crate_type = "lib"] #[no_mangle] pub fn all_zero(data: &[u64]) -> bool { // CHECK-LABEL: @all_zero( // CHECK: [[PHI:%.*]] = phi i1 // CHECK-NOT: phi i8 // CHECK-NOT: zext data.iter().copied().fold(true, |acc, x| acc & (x == 0)) } </ins>

<ins> // compile-flags: -O // min-llvm-version: 16 // ignore-debug: the debug assertions get in the way #![crate_type = "lib"] #[no_mangle] pub fn test() -> usize { // CHECK-LABEL: @test( // CHECK: ret {{i64|i32}} 165 let values = [23, 16, 54, 3, 60, 9]; let mut acc = 0; for item in values { acc += item; } acc } </ins>

<ins> // compile-flags: -O // min-llvm-version: 16 // ignore-debug: the debug assertions get in the way #![crate_type = "lib"] #[no_mangle] pub fn test(a: [i32; 10]) -> i32 { // CHECK-LABEL: @test( // CHECK: [[L1:%.+]] = load i32 // CHECK: [[L2:%.+]] = load i32 // CHECK: [[R:%.+]] = add i32 [[L1]], [[L2]] // CHECK: ret i32 [[R]] let mut sum = 0; for v in a.iter().skip(8) { sum += v; } sum } </ins>

<ins> // compile-flags: -O -C overflow-checks // min-llvm-version: 16 #![crate_type = "lib"] #[no_mangle] pub fn test(arr: &[u8], weight: u32) { // CHECK-LABEL: @test( // CHECK-NOT: panic let weight = weight.min(256 * 256 * 256); for x in arr { assert!(weight <= 256 * 256 * 256); let result = *x as u32 * weight; } } </ins>

<ins> // compile-flags: -O // min-llvm-version: 16 #![crate_type = "lib"] #[no_mangle] pub fn test(a: i32, b: i32) -> bool { // CHECK-LABEL: @test( // CHECK: ret i1 true let c1 = (a >= 0) && (a <= 10); let c2 = (b >= 0) && (b <= 20); if c1 & c2 { a + 100 != b } else { true } } </ins>

<ins> // compile-flags: -O // min-llvm-version: 16 #![crate_type = "lib"] #[no_mangle] pub fn test() -> u32 { // CHECK-LABEL: @test( // CHECK: ret i32 13 let s = [1, 2, 3, 4, 5, 6, 7]; let mut iter = s.iter(); let mut sum = 0; while let Some(_) = iter.next() { sum += iter.next().map_or(1, |&x| x) } sum } </ins>

<ins> // compile-flags: -O // min-llvm-version: 16 #![crate_type = "lib"] #[no_mangle] pub fn test(dividend: i64, divisor: i64) -> Option<i64> { // CHECK-LABEL: @test( // CHECK-NOT: panic if dividend > i64::min_value() && divisor != 0 { Some(dividend / divisor) } else { None } } </ins>