Change:
I'm trying to figure out why certain iterator-based algorithms get const-optimized, while others don't and I stumbled upon this case. (updated 2021.03.05) Compiling results in the expected machine code, but has extra stack reserve/free instructions that are not necessary, since the function's contents are optimized away completely. The stack size equals the size of the array.
Two observations: in this case optimize code better than Just like , adding to array in fn2 also make it optimizable.
This would very likely be fixed by
Fixed by
There should be codegen test for this issue.
Yeah, right. I can add those for the issues I closed.
Actually, I'm reopening this one as the issue stands on ARM:
Looks like a phase ordering problem. The remaining IR would be eliminated by GVN + InstCombine. Currently it only gets eliminated by DAGCombine, thus you still see the prologue/epilogue on ARM.
The problem here is that this loop only gets unrolled during full loop unrolling, while we need it to be unrolled during simple unrolling to still have a chance to optimize. For the IR at that point, SCEV cannot determine the loop trip count:
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>