Skip to content

block-placement LLVM pass introduces superfluous instruction in unrolled loop #145176

@kotauskas

Description

@kotauskas

Since Rust code is affected by this, and because Rustc uses a fork of LLVM, I'm reporting this here, although the same issue probably affects other LLVM-based compilers.

The following code:

fn check(b: u8) -> Option<u8> {
    if let 1..=127 = b { Some(b) } else { None }
}
pub fn conv(bytes: [u8; 4]) -> Option<u32> {
    bytes
        .into_iter()
        .try_fold(0, |sum, ch| {
            check(ch).map(|digit| sum + u32::from(digit))
        })
}

has this at the end of its assembly output:

        mov eax, 1
        ret
.LBB0_5:
        ret

Here it is on Godbolt.

.LBB0_5 could've been moved before the ret, reducing the number of rets in the function to 1. In fact, the LLVM IR only contains one ret up until the block placement pass, as can be seen in the optimization pipeline viewer on Godbolt.

Meta

rustc --version --verbose:

rustc 1.91.0-nightly (de3efa79f 2025-08-08)
binary: rustc
commit-hash: de3efa79f95852c7427587f1d535bfea7c0d6779
commit-date: 2025-08-08
host: x86_64-unknown-linux-gnu
release: 1.91.0-nightly
LLVM version: 21.1.0
Internal compiler ID: nightly

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.I-heavyIssue: Problems and improvements with respect to binary size of generated code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions