rust-lang / rust-lang/rust

Extra instructions in `as_chunks` remainder loop between beta and nightly

Open
#147,459 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-codegen C-bug P-medium regression-from-stable-to-stable T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

While working on https://github.com/rust-lang/rust/pull/147436, I noticed a regression in codegen between nightly and stable 1.90/beta.

Code
I tried this code that checks two slices for ASCII equality ignoring case, a modification of the current implementation.
#[inline(never)]
pub const fn eq_ignore_ascii_case_chunks(s: &[u8], other: &[u8]) -> bool {
    if s.len() != other.len() {
        return false;
    }

    const N: usize = 16;
    let (a, a_rem) = s.as_chunks::<N>();
    let (b, b_rem) = other.as_chunks::<N>();

    let mut i = 0;
    while i < a.len() && i < b.len() {
        let mut equal_ascii = true;
        let mut j = 0;
        while j < N {
            equal_ascii &= a[i][j].eq_ignore_ascii_case(&b[i][j]);
            j += 1;
        }

        if !equal_ascii {
            return false;
        }

        i += 1;
    }

    let mut a = a_rem;
    let mut b = b_rem;

    while let ([first_a, rest_a @ ..], [first_b, rest_b @ ..]) = (a, b) {
        if first_a.eq_ignore_ascii_case(&first_b) {
            a = rest_a;
            b = rest_b;
        } else {
            return false;
        }
    }

    true
}

https://rust.godbolt.org/z/17zKoqGvc

The remainder loop should look like this

.LBB0_8:
        cmp     rsi, rcx
        sete    al
        je      .LBB0_2
        ;; elided, identical in both outputs
        je      .LBB0_8
.LBB0_2:
        ret
.LBB0_1:
        xor     eax, eax
        ret

Instead, there are extra or, test, and and instructions in nightly.

.LBB0_8:
        cmp     rsi, rcx
        sete    al
        or      al, al
        test    al, 1
        jne     .LBB0_2
        ;; elided, identical in both outputs
        je      .LBB0_8
.LBB0_2:
        and     al, 1
        ret
.LBB0_1:
        xor     eax, eax
        and     al, 1
        ret

The LLVM IR differs in this block, where the regressed form uses a select and the "good" version uses or.

nightly

bb20:
  %b_rem.sroa.5.0 = phi i64 [ %rest_b.1, %bb22 ], [ %1, %bb20.preheader ]
  %b_rem.sroa.0.0 = phi ptr [ %rest_b.0, %bb22 ], [ %3, %bb20.preheader ]
  %a_rem.sroa.5.0 = phi i64 [ %rest_a.1, %bb22 ], [ %1, %bb20.preheader ]
  %a_rem.sroa.0.0 = phi ptr [ %rest_a.0, %bb22 ], [ %0, %bb20.preheader ]
  %_37.not = icmp eq i64 %a_rem.sroa.5.0, 0
  %_35.not = icmp eq i64 %b_rem.sroa.5.0, 0
  %or.cond21 = select i1 %_37.not, i1 true, i1 %_35.not
  br i1 %or.cond21, label %bb27, label %bb22

stable

bb20:
  %b.sroa.6.0 = phi i64 [ %rest_b.1, %bb22 ], [ %1, %bb20.preheader ]
  %b.sroa.0.0 = phi ptr [ %rest_b.0, %bb22 ], [ %3, %bb20.preheader ]
  %a.sroa.6.0 = phi i64 [ %rest_a.1, %bb22 ], [ %1, %bb20.preheader ]
  %a.sroa.0.0 = phi ptr [ %rest_a.0, %bb22 ], [ %0, %bb20.preheader ]
  %_42 = icmp eq i64 %a.sroa.6.0, 0
  %_40 = icmp eq i64 %b.sroa.6.0, 0
  %or.cond.not = or i1 %_40, %_42
  br i1 %or.cond.not, label %bb27, label %bb22
Version it worked on

It most recently worked on:

binary: rustc
commit-hash: aa7859c0dec2de6c9cab34b03028bcef7b1fc25d
commit-date: 2025-09-27
host: x86_64-unknown-linux-gnu
release: 1.91.0-beta.4
LLVM version: 21.1.1
Internal compiler ID: beta
Version with regression

Playground nightly

Build using the Nightly version: 1.92.0-nightly
(2025-10-06 3d8c1c1fc077d04658de)

@rustbot modify labels: +regression-from-stable-to-nightly -regression-untriaged

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the provided Rust reproducer in the linked Compiler Explorer and compare the LLVM IR and assembly from beta 1.91.0-beta.4 with nightly 1.92.0. Trace the compiler change responsible for the select-based remainder-loop condition; done means the nightly output no longer contains the extra instructions and matches the expected form.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.