Skip to content

Improve bounds check for function that always return in-bounds index #98258

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

Open
Pzixel opened this issue Jun 19, 2022 · 7 comments
Open

Improve bounds check for function that always return in-bounds index #98258

Pzixel opened this issue Jun 19, 2022 · 7 comments
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-optimization Category: An issue highlighting optimization opportunities or PRs implementing such I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Pzixel
Copy link

Pzixel commented Jun 19, 2022

Consider following function:

pub fn foo(mut a: Vec<u64>) -> Vec<u64> {
    let val = 15;
    if let Err(idx) = a.binary_search(&val) {
        a.insert(idx, val);
    }
    a
}

On current rust 1.61.0 you can expect following output:

...
.LBB3_12:
        mov     rdi, rbx
        mov     rsi, r12
        call    qword ptr [rip + alloc::vec::Vec<T,A>::insert::assert_failed@GOTPCREL]
        ud2
...

It would be nice to have some attribute or other way of saying that binary search is always returning a valid insert index and bounds check should be eliminated. You can get an expected output in current rustc versions via:

pub fn foo(mut a: Vec<u64>) -> Vec<u64> {
    let val = 15;
    if let Err(idx) = a.binary_search(&val) {
        if idx > a.len() {
            unsafe { std::hint::unreachable_unchecked() };
        }
        a.insert(idx, val);
    }
    a
}

Since performing a search and then inserting is one of main binary_search use cases it might be worthwhile to implement such an optimization.
See godbolt link for a whole example

@Pzixel Pzixel closed this as completed Jun 19, 2022
@Pzixel Pzixel reopened this Jun 19, 2022
@leonardo-m
Copy link

The solution is to add refinement typing in Rust:
https://antelang.org/docs/language/#refinement-types

@Pzixel
Copy link
Author

Pzixel commented Jun 19, 2022

Well while refinement types are great I think rust may just go with what is already supported. For example if we replace Err with Ok then it can see that index is no bigger than a.len() and removes the assert_failed. It just about implementing a bit more sophisticated heuristics.

@leonardo-m
Copy link

Well, refinement typing is a more general solution, you can use for much more than this case of binary_search :)

@the8472
Copy link
Member

the8472 commented Jun 19, 2022

Have you benchmarked this? Inserting in the middle of a vec incurs O(n) cost for the shifting, that likely dwarves the cost of the bounds check so the optimization may not be worth it.

@Pzixel
Copy link
Author

Pzixel commented Jun 19, 2022

Well right, but inserting in the end of a vec incurs no costs for the shifting. I can also imagine this might come with some unexpected benefits in other functions and/or scenarios.

@scottmcm
Copy link
Member

scottmcm commented Oct 1, 2022

I've got a PR open that might improve this: #102535

(It'll definitely help for some slice methods, but I'm unsure about Vec ones, since the bounds checking is more complicated when Deref is involved.)

@clubby789
Copy link
Contributor

@rustbot label +A-llvm +I-slow
Looks like the call to insert::assert_failed is still there

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. I-slow Issue: Problems and improvements with respect to performance of generated code. labels Mar 27, 2023
@Noratrieb Noratrieb added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 5, 2023
@workingjubilee workingjubilee added the C-optimization Category: An issue highlighting optimization opportunities or PRs implementing such label Feb 14, 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-optimization Category: An issue highlighting optimization opportunities or PRs implementing such I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

8 participants