Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: I expected to see this happen: all three versions of the loop body have no overflow checks and are optimized out. Instead, this happened: has no overflow checks whereas the two other versions do have overflow checks on 1.64.0 and below, and on beta/nightly all versions have overflow checks. Also, uncommenting line , which makes bound one smaller, makes all three versions have no overflow checks on both 1.64.0 and nightly, which is extra weird because the bounds are satisfied with either value.
IR test case: I'd generally expect CVP to handle this, but: Apparently, LVI fails to determine the range of a value that is used inside a loop. Sinking the umin into does fold. There's two possible fixes here. One would be to support this in LVI. The other would be to add with.overflow support to SCCP.
Upstream patch:
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>