Skip to content

Commit 2a52a46

Browse files
committed
Add assumes to avoid bounds checks
Surprisingly the compiler removed these bounds checks automatically when targeting x86_64, but not on aarch64.
1 parent 5038a49 commit 2a52a46

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

library/alloc/src/str.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -623,9 +623,15 @@ fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
623623
let mut i = 0_usize;
624624

625625
// process the input in chunks to enable auto-vectorization
626+
let mut is_ascii = [false; N];
626627
while slice.len() >= N {
628+
// Safety: out_slice was allocated with same lengths as input slice and gets updated with
629+
// the same offsets
630+
unsafe {
631+
core::intrinsics::assume(slice.len() == out_slice.len());
632+
}
633+
627634
let chunk = &slice[..N];
628-
let mut is_ascii = [false; N];
629635

630636
for j in 0..N {
631637
is_ascii[j] = chunk[j] <= 127;
@@ -634,7 +640,7 @@ fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
634640
// auto-vectorization for this check is a bit fragile,
635641
// sum and comparing against the chunk size gives the best result,
636642
// specifically a pmovmsk instruction on x86.
637-
if is_ascii.into_iter().map(|x| x as u8).sum::<u8>() as usize != N {
643+
if is_ascii.iter().map(|x| *x as u8).sum::<u8>() as usize != N {
638644
break;
639645
}
640646

@@ -649,6 +655,12 @@ fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
649655

650656
// handle the remainder as individual bytes
651657
while !slice.is_empty() {
658+
// Safety: out_slice was allocated with same lengths as input slice and gets updated with
659+
// the same offsets
660+
unsafe {
661+
core::intrinsics::assume(slice.len() == out_slice.len());
662+
}
663+
652664
let byte = slice[0];
653665
if byte > 127 {
654666
break;

0 commit comments

Comments
 (0)