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: The loop should be inlined because is const-known. For example, here is the generated assembly on Rust 1.63.0 () and Rust Beta (): Instead, this happened: On nightly, the loop is inlined. However, the entire function is not computed despite the stable and beta Rust inlining it. Here is the generated assembly on Nightly (): n/a - disclosed at usages Keywords: const inline loop, const loop, const loop not evaluated Relevant discord thread:
label regression-from-stable-to-nightly
label I-slow
WG-prioritization assigning priority (). label -I-prioritize +P-high t-compiler
Partial fix: This at least allows the loop to be unrolled, though it only gets fully constant folded in the backend.
Oh my, if it isn't yet another casualty of LLVM's dumb typed GEP representation. This might get fixed by as well.
This turns out to be surprisingly tricky due to phase ordering issues. Even with canonical GEPs, the loop bounds only become known after full unrolling, by which point it is too late. I think the best shot at this would be to generalize LICM scalar promotion to perform load promotion in the presence of potentially aliasing loads. is preparation to move in that direction.
for improved LICM promotion. Still needs to be combined with canonical GEPs to work.
what are your thoughts on this ticket? Your was merged, but the other LLVM changes have not. Meanwhile, it seems like has stalled, but nikic r+'ed it apart from wanting a FIXME removed, does that sound right? (I went ahead and a commit to remove the FIXME.) And its not clear whether would actually resolve this, is that correct?
We need both and to fully resolve this, as far as I remember. We should probably land ASAP to give us a chance to address regressions from it in LLVM 16.
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>