Change:
Consider the following functions (): These functions have identical behavior: they map to . In the former case, LLVM generates a nice lookup table for us, but in the latter, it emits an extra branch. The only difference is that I've used to avoid needing to write an unreachable-by-optimization branch. If we look at the generated IR (after ): The problem is clear: LLVM does not seem to realize that it can trivially transform to here, by observing that the default in the is only taken when . I suspect this is more LLVM bug than Rust bug, but it feels fixable by a MIR peephole optimization? Unclear. The code I wrote is an attractive nuisance that I imagine other people writing, too, so perhaps there is value to seeing if this optimization can be made before LLVM. This bug is also present in Clang, in case someone wants to file an LLVM bug: It's unclear to me if this is the sort of optimization Clang would do in the frontend instead of in LLVM; could go either-or here, tbh. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Upstream issue: claim
label llvm-fixed-upstream
It looks like this is fixed since 1.75, but I don't know what fixed it:
I don't think it has been fixed. It looks like the function is not submitted: Bisected to cc
You need to stick or on the function otherwise when CE compiles the crate the function is only lowered to MIR as if it has the attribute.
Normally I would do this. Maybe we should mention this somewhere to avoid submitting invalid code to godbolt?
Oops, sorry. I saw that one function was generated and assumed the other one got merged...
Seems like this has been reverted :/, look at the generated assembly with
Can you explain why you think that? I don't see any changes: BTW, I can reland the upstream patch now.
I think that it's been reverted because the assembly output contains this: The branch still has some branching (this can also be seen on the LLVM IR, has 12 lines and 2 jumps, while has four lines and no branches)
Ah, I think you're saying that this optimization is still in a missing state, right?
Yep, I thought you meant that you implemented the optimization, is it not implemented? :sweat_smile:
Yes, I have implemented it, but due to the compilation time issue mentioned in , I had to revert the commit. Now I have relanded it: label +llvm-fixed-upstream
Confirmed fixed by , needs codegen test.

Discussion:
<ins> //@ compile-flags: -O //@ min-llvm-version: 19 // Test for #107681. // Make sure we don't create `br` or `select` instructions. #![crate_type = "lib"] use std::iter::Copied; use std::slice::Iter; #[no_mangle] pub unsafe fn foo(x: &mut Copied<Iter<'_, u32>>) -> u32 { // CHECK-LABEL: @foo( // CHECK-NOT: br // CHECK-NOT: select // CHECK: [[RET:%.*]] = load i32, ptr // CHECK-NEXT: ret i32 [[RET]] x.next().unwrap_unchecked() } </ins>

<ins> //@ compile-flags: -O //@ min-llvm-version: 19 //@ only-x86_64 // Test for #118306. // Make sure we don't create `br` or `select` instructions. #![crate_type = "lib"] #[no_mangle] pub fn branchy(input: u64) -> u64 { // CHECK-LABEL: @branchy( // CHECK-NEXT:  start: // CHECK-NEXT:    [[_2:%.*]] = and i64 [[INPUT:%.*]], 3 // CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i64], ptr @switch.table.branchy, i64 0, i64 [[_2]] // CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load i64, ptr [[SWITCH_GEP]] // CHECK-NEXT:    ret i64 [[SWITCH_LOAD]] match input % 4 { 1 | 2 => 1, 3 => 2, _ => 0, } } </ins>

<ins> //@ compile-flags: -Copt-level=s //@ min-llvm-version: 19 //@ only-x86_64 // Test for #126585. // Ensure that this IR doesn't have extra undef phi input, which also guarantees that this asm // doesn't have subsequent labels and unnecessary `jmp` instructions. #![crate_type = "lib"] #[no_mangle] fn checked_div_round(a: u64, b: u64) -> Option<u64> { // CHECK-LABEL: @checked_div_round // CHECK: phi // CHECK-NOT: undef // CHECK: phi // CHECK-NOT: undef match b { 0 => None, 1 => Some(a), // `a / b` is computable and `(a % b) * 2` can not overflow since `b >= 2`. b => Some(a / b + if (a % b) * 2 >= b { 1 } else { 0 }), } } </ins>