Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler do not remove slice bounds checks if index is guaranteed to be less than part of the length #110971

Open
AngelicosPhosphoros opened this issue Apr 29, 2023 · 4 comments
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. I-slow Issue: Problems and improvements with respect to performance of generated code.

Comments

@AngelicosPhosphoros
Copy link
Contributor

I tried this code:

pub fn test_assert(arr: &[u32], j: usize)->u32{
    assert!(j < arr.len() / 2);
    arr[j]
}

I expected to see this happen: Since for any nonnegative integer i / 2 < i, j < i / 2 implies that j < i so we should not have bounds check here at indexing.

Instead, this happened: Function checks j twice: first for len / 2 then for len, and generates all code for panics.

example::test_assert:
        push    rax
        mov     rax, rsi
        shr     rax
        cmp     rax, rdx
        jbe     .LBB0_3
        cmp     rdx, rsi
        jae     .LBB0_2
        mov     eax, dword ptr [rdi + 4*rdx]
        pop     rcx
        ret
.LBB0_2:
        lea     rax, [rip + .L__unnamed_1]
        mov     rdi, rdx
        mov     rdx, rax
        call    qword ptr [rip + core::panicking::panic_bounds_check@GOTPCREL]
        ud2
.LBB0_3:
        lea     rdi, [rip + .L__unnamed_2]
        lea     rdx, [rip + .L__unnamed_3]
        mov     esi, 35
        call    qword ptr [rip + core::panicking::panic@GOTPCREL]
        ud2

I noticed, that if we shorten slice first, it can remove bounds checks. E.g. this code doesn't generate any bounds checks:

pub fn test_unreachable2(arr: &[u32], j: usize)->u32{
    let arr = &arr[..arr.len() / 2];
    if j >= arr.len() {
        unsafe {
            unreachable_unchecked();
        }
    }
    arr[j]
}
example::test_unreachable2:
        mov     eax, dword ptr [rdi + 4*rdx]
        ret

Meta

rustc --version --verbose:

rustc 1.69.0 (84c898d65 2023-04-16)
binary: rustc
commit-hash: 84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc
commit-date: 2023-04-16
host: x86_64-unknown-linux-gnu
release: 1.69.0
LLVM version: 15.0.7

Godbolt link.

@AngelicosPhosphoros AngelicosPhosphoros added the C-bug Category: This is a bug. label Apr 29, 2023
@AngelicosPhosphoros
Copy link
Contributor Author

Clang has same behaviour: llvm/llvm-project#62441

@jyn514 jyn514 added I-slow Issue: Problems and improvements with respect to performance of generated code. A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. labels Apr 29, 2023
@caojoshua
Copy link

submitted fix for review in LLVM in https://reviews.llvm.org/D151541

I'm not familiar with rustc project, so I don't know how to test this. The patch fixes the clang case, and should pass the rustc case from what I see in the IR.

@gustav3d
Copy link

Well, this is great news indeed.

caojoshua added a commit to llvm/llvm-project that referenced this issue Jun 7, 2023
`V1 >> V2 u<= V1` for any V1, V2

This works for lshr and any div's that are changed to lshr's

This fixes issues in clang and rustc:
#62441
rust-lang/rust#110971

Reviewed By: goldstein.w.n

Differential Revision: https://reviews.llvm.org/D151541
@veera-sivarajan
Copy link
Contributor

fixed since rustc 1.78.0: https://rust.godbolt.org/z/vn9YEeofe

@rustbot label +e-needs-test

@rustbot rustbot added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Mar 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. I-slow Issue: Problems and improvements with respect to performance of generated code.
Projects
None yet
Development

No branches or pull requests

7 participants
@gustav3d @AngelicosPhosphoros @jyn514 @veera-sivarajan @caojoshua @rustbot and others