mirror of
https://github.com/openharmony/third_party_rust_encoding_rs.git
synced 2026-07-21 02:05:23 -04:00
Merge NEON support.
This commit is contained in:
+1
-1
@@ -21,7 +21,7 @@ no-static-ideograph-encoder-tables = []
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "0.1.0"
|
||||
simd = { version = "0.2.0", optional = true }
|
||||
simd = { version = "0.2.2", optional = true }
|
||||
serde = { version = "1.0", optional = true }
|
||||
# rayon = { version = "0.8.0", optional = true }
|
||||
|
||||
|
||||
+171
-144
@@ -22,7 +22,7 @@
|
||||
// different approaches based on benchmarking on Raspberry Pi 3.
|
||||
|
||||
#[cfg(all(feature = "simd-accel",
|
||||
any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"))))]
|
||||
any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"), all(target_endian = "little", target_feature = "neon"))))]
|
||||
use simd_funcs::*;
|
||||
|
||||
// `as` truncates, so works on 32-bit, too.
|
||||
@@ -70,12 +70,12 @@ macro_rules! ascii_alu {
|
||||
// to alignment.
|
||||
// if ::std::mem::size_of::<$src_unit>() == ::std::mem::size_of::<$dst_unit>() {
|
||||
// ascii_to_ascii
|
||||
let src_alignment = (src as usize) & ALIGNMENT_MASK;
|
||||
let dst_alignment = (dst as usize) & ALIGNMENT_MASK;
|
||||
let src_alignment = (src as usize) & ALU_ALIGNMENT_MASK;
|
||||
let dst_alignment = (dst as usize) & ALU_ALIGNMENT_MASK;
|
||||
if src_alignment != dst_alignment {
|
||||
break;
|
||||
}
|
||||
(ALIGNMENT - src_alignment) & ALIGNMENT_MASK
|
||||
(ALU_ALIGNMENT - src_alignment) & ALU_ALIGNMENT_MASK
|
||||
// } else if ::std::mem::size_of::<$src_unit>() < ::std::mem::size_of::<$dst_unit>() {
|
||||
// ascii_to_basic_latin
|
||||
// let src_until_alignment = (ALIGNMENT - ((src as usize) & ALIGNMENT_MASK)) & ALIGNMENT_MASK;
|
||||
@@ -92,7 +92,7 @@ macro_rules! ascii_alu {
|
||||
// dst_until_alignment
|
||||
// }
|
||||
};
|
||||
if until_alignment + STRIDE_SIZE <= len {
|
||||
if until_alignment + ALU_STRIDE_SIZE <= len {
|
||||
// Moving pointers to alignment seems to be a pessimization on
|
||||
// x86_64 for operations that have UTF-16 as the internal
|
||||
// Unicode representation. However, since it seems to be a win
|
||||
@@ -110,14 +110,14 @@ macro_rules! ascii_alu {
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
let len_minus_stride = len - ALU_STRIDE_SIZE;
|
||||
loop {
|
||||
if let Some(num_ascii) = $stride_fn(src.offset(offset as isize) as *const usize,
|
||||
dst.offset(offset as isize) as *mut usize) {
|
||||
offset += num_ascii;
|
||||
return Some((*(src.offset(offset as isize)), offset));
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += ALU_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -163,21 +163,21 @@ macro_rules! basic_latin_alu {
|
||||
// } else
|
||||
if ::std::mem::size_of::<$src_unit>() < ::std::mem::size_of::<$dst_unit>() {
|
||||
// ascii_to_basic_latin
|
||||
let src_until_alignment = (ALIGNMENT - ((src as usize) & ALIGNMENT_MASK)) & ALIGNMENT_MASK;
|
||||
if (dst.offset(src_until_alignment as isize) as usize) & ALIGNMENT_MASK != 0 {
|
||||
let src_until_alignment = (ALU_ALIGNMENT - ((src as usize) & ALU_ALIGNMENT_MASK)) & ALU_ALIGNMENT_MASK;
|
||||
if (dst.offset(src_until_alignment as isize) as usize) & ALU_ALIGNMENT_MASK != 0 {
|
||||
break;
|
||||
}
|
||||
src_until_alignment
|
||||
} else {
|
||||
// basic_latin_to_ascii
|
||||
let dst_until_alignment = (ALIGNMENT - ((dst as usize) & ALIGNMENT_MASK)) & ALIGNMENT_MASK;
|
||||
if (src.offset(dst_until_alignment as isize) as usize) & ALIGNMENT_MASK != 0 {
|
||||
let dst_until_alignment = (ALU_ALIGNMENT - ((dst as usize) & ALU_ALIGNMENT_MASK)) & ALU_ALIGNMENT_MASK;
|
||||
if (src.offset(dst_until_alignment as isize) as usize) & ALU_ALIGNMENT_MASK != 0 {
|
||||
break;
|
||||
}
|
||||
dst_until_alignment
|
||||
}
|
||||
};
|
||||
if until_alignment + STRIDE_SIZE <= len {
|
||||
if until_alignment + ALU_STRIDE_SIZE <= len {
|
||||
// Moving pointers to alignment seems to be a pessimization on
|
||||
// x86_64 for operations that have UTF-16 as the internal
|
||||
// Unicode representation. However, since it seems to be a win
|
||||
@@ -195,13 +195,13 @@ macro_rules! basic_latin_alu {
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
let len_minus_stride = len - ALU_STRIDE_SIZE;
|
||||
loop {
|
||||
if !$stride_fn(src.offset(offset as isize) as *const usize,
|
||||
dst.offset(offset as isize) as *mut usize) {
|
||||
break;
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += ALU_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -236,32 +236,32 @@ macro_rules! latin1_alu {
|
||||
let mut until_alignment = {
|
||||
if ::std::mem::size_of::<$src_unit>() < ::std::mem::size_of::<$dst_unit>() {
|
||||
// unpack
|
||||
let src_until_alignment = (ALIGNMENT - ((src as usize) & ALIGNMENT_MASK)) & ALIGNMENT_MASK;
|
||||
if (dst.offset(src_until_alignment as isize) as usize) & ALIGNMENT_MASK != 0 {
|
||||
let src_until_alignment = (ALU_ALIGNMENT - ((src as usize) & ALU_ALIGNMENT_MASK)) & ALU_ALIGNMENT_MASK;
|
||||
if (dst.offset(src_until_alignment as isize) as usize) & ALU_ALIGNMENT_MASK != 0 {
|
||||
break;
|
||||
}
|
||||
src_until_alignment
|
||||
} else {
|
||||
// pack
|
||||
let dst_until_alignment = (ALIGNMENT - ((dst as usize) & ALIGNMENT_MASK)) & ALIGNMENT_MASK;
|
||||
if (src.offset(dst_until_alignment as isize) as usize) & ALIGNMENT_MASK != 0 {
|
||||
let dst_until_alignment = (ALU_ALIGNMENT - ((dst as usize) & ALU_ALIGNMENT_MASK)) & ALU_ALIGNMENT_MASK;
|
||||
if (src.offset(dst_until_alignment as isize) as usize) & ALU_ALIGNMENT_MASK != 0 {
|
||||
break;
|
||||
}
|
||||
dst_until_alignment
|
||||
}
|
||||
};
|
||||
if until_alignment + STRIDE_SIZE <= len {
|
||||
if until_alignment + ALU_STRIDE_SIZE <= len {
|
||||
while until_alignment != 0 {
|
||||
let code_unit = *(src.offset(offset as isize));
|
||||
*(dst.offset(offset as isize)) = code_unit as $dst_unit;
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
let len_minus_stride = len - ALU_STRIDE_SIZE;
|
||||
loop {
|
||||
$stride_fn(src.offset(offset as isize) as *const usize,
|
||||
dst.offset(offset as isize) as *mut usize);
|
||||
offset += STRIDE_SIZE;
|
||||
offset += ALU_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -289,22 +289,22 @@ macro_rules! ascii_simd_check_align {
|
||||
#[inline(always)]
|
||||
pub unsafe fn $name(src: *const $src_unit, dst: *mut $dst_unit, len: usize) -> Option<($src_unit, usize)> {
|
||||
let mut offset = 0usize;
|
||||
if STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
if SIMD_STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE;
|
||||
// XXX Should we first process one stride unconditinoally as unaligned to
|
||||
// avoid the cost of the branchiness below if the first stride fails anyway?
|
||||
// XXX Should we just use unaligned SSE2 access unconditionally? It seems that
|
||||
// on Haswell, it would make sense to just use unaligned and not bother
|
||||
// checking. Need to benchmark older architectures before deciding.
|
||||
let dst_masked = (dst as usize) & ALIGNMENT_MASK;
|
||||
if ((src as usize) & ALIGNMENT_MASK) == 0 {
|
||||
let dst_masked = (dst as usize) & SIMD_ALIGNMENT_MASK;
|
||||
if ((src as usize) & SIMD_ALIGNMENT_MASK) == 0 {
|
||||
if dst_masked == 0 {
|
||||
loop {
|
||||
if !$stride_both_aligned(src.offset(offset as isize),
|
||||
dst.offset(offset as isize)) {
|
||||
break;
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ macro_rules! ascii_simd_check_align {
|
||||
dst.offset(offset as isize)) {
|
||||
break;
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -328,7 +328,7 @@ macro_rules! ascii_simd_check_align {
|
||||
dst.offset(offset as isize)) {
|
||||
break;
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -339,7 +339,7 @@ macro_rules! ascii_simd_check_align {
|
||||
dst.offset(offset as isize)) {
|
||||
break;
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -371,20 +371,20 @@ macro_rules! latin1_simd_check_align {
|
||||
#[inline(always)]
|
||||
pub unsafe fn $name(src: *const $src_unit, dst: *mut $dst_unit, len: usize) {
|
||||
let mut offset = 0usize;
|
||||
if STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
if SIMD_STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE;
|
||||
// XXX Should we first process one stride unconditinoally as unaligned to
|
||||
// avoid the cost of the branchiness below if the first stride fails anyway?
|
||||
// XXX Should we just use unaligned SSE2 access unconditionally? It seems that
|
||||
// on Haswell, it would make sense to just use unaligned and not bother
|
||||
// checking. Need to benchmark older architectures before deciding.
|
||||
let dst_masked = (dst as usize) & ALIGNMENT_MASK;
|
||||
if ((src as usize) & ALIGNMENT_MASK) == 0 {
|
||||
let dst_masked = (dst as usize) & SIMD_ALIGNMENT_MASK;
|
||||
if ((src as usize) & SIMD_ALIGNMENT_MASK) == 0 {
|
||||
if dst_masked == 0 {
|
||||
loop {
|
||||
$stride_both_aligned(src.offset(offset as isize),
|
||||
dst.offset(offset as isize));
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -393,7 +393,7 @@ macro_rules! latin1_simd_check_align {
|
||||
loop {
|
||||
$stride_src_aligned(src.offset(offset as isize),
|
||||
dst.offset(offset as isize));
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -404,7 +404,7 @@ macro_rules! latin1_simd_check_align {
|
||||
loop {
|
||||
$stride_dst_aligned(src.offset(offset as isize),
|
||||
dst.offset(offset as isize));
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -413,7 +413,7 @@ macro_rules! latin1_simd_check_align {
|
||||
loop {
|
||||
$stride_neither_aligned(src.offset(offset as isize),
|
||||
dst.offset(offset as isize));
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -451,14 +451,14 @@ macro_rules! ascii_simd_unalign {
|
||||
#[inline(always)]
|
||||
pub unsafe fn $name(src: *const $src_unit, dst: *mut $dst_unit, len: usize) -> Option<($src_unit, usize)> {
|
||||
let mut offset = 0usize;
|
||||
if STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
if SIMD_STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE;
|
||||
loop {
|
||||
if !$stride_neither_aligned(src.offset(offset as isize),
|
||||
dst.offset(offset as isize)) {
|
||||
break;
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -485,12 +485,12 @@ macro_rules! latin1_simd_unalign {
|
||||
#[inline(always)]
|
||||
pub unsafe fn $name(src: *const $src_unit, dst: *mut $dst_unit, len: usize) {
|
||||
let mut offset = 0usize;
|
||||
if STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
if SIMD_STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE;
|
||||
loop {
|
||||
$stride_neither_aligned(src.offset(offset as isize),
|
||||
dst.offset(offset as isize));
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -587,7 +587,9 @@ cfg_if! {
|
||||
if #[cfg(all(feature = "simd-accel", target_endian = "little", target_arch = "aarch64"))] {
|
||||
// SIMD with the same instructions for aligned and unaligned loads and stores
|
||||
|
||||
pub const STRIDE_SIZE: usize = 16;
|
||||
pub const SIMD_STRIDE_SIZE: usize = 16;
|
||||
|
||||
pub const MAX_STRIDE_SIZE: usize = 16;
|
||||
|
||||
// pub const ALIGNMENT: usize = 8;
|
||||
|
||||
@@ -604,16 +606,18 @@ cfg_if! {
|
||||
ascii_simd_unalign!(basic_latin_to_ascii, u16, u8, basic_latin_to_ascii_stride_neither_aligned);
|
||||
latin1_simd_unalign!(unpack_latin1, u8, u16, unpack_stride_neither_aligned);
|
||||
latin1_simd_unalign!(pack_latin1, u16, u8, pack_stride_neither_aligned);
|
||||
} else if #[cfg(all(feature = "simd-accel", target_feature = "sse2"))] {
|
||||
} else if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_feature = "neon"))))] {
|
||||
// SIMD with different instructions for aligned and unaligned loads and stores.
|
||||
//
|
||||
// Newer microarchitectures are not supposed to have a performance difference between
|
||||
// aligned and unaligned SSE2 loads and stores when the address is actually aligned,
|
||||
// but the benchmark results I see don't agree.
|
||||
|
||||
pub const STRIDE_SIZE: usize = 16;
|
||||
pub const SIMD_STRIDE_SIZE: usize = 16;
|
||||
|
||||
pub const ALIGNMENT_MASK: usize = 15;
|
||||
pub const MAX_STRIDE_SIZE: usize = 16;
|
||||
|
||||
pub const SIMD_ALIGNMENT_MASK: usize = 15;
|
||||
|
||||
ascii_to_ascii_simd_stride!(ascii_to_ascii_stride_both_aligned, load16_aligned, store16_aligned);
|
||||
ascii_to_ascii_simd_stride!(ascii_to_ascii_stride_src_aligned, load16_aligned, store16_unaligned);
|
||||
@@ -648,11 +652,13 @@ cfg_if! {
|
||||
} else if #[cfg(all(target_endian = "little", target_pointer_width = "64"))] {
|
||||
// Aligned ALU word, little-endian, 64-bit
|
||||
|
||||
pub const STRIDE_SIZE: usize = 16;
|
||||
pub const ALU_STRIDE_SIZE: usize = 16;
|
||||
|
||||
pub const ALIGNMENT: usize = 8;
|
||||
pub const MAX_STRIDE_SIZE: usize = 16;
|
||||
|
||||
pub const ALIGNMENT_MASK: usize = 7;
|
||||
pub const ALU_ALIGNMENT: usize = 8;
|
||||
|
||||
pub const ALU_ALIGNMENT_MASK: usize = 7;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn unpack_alu(word: usize, second_word: usize, dst: *mut usize) {
|
||||
@@ -702,11 +708,13 @@ cfg_if! {
|
||||
} else if #[cfg(all(target_endian = "little", target_pointer_width = "32"))] {
|
||||
// Aligned ALU word, little-endian, 32-bit
|
||||
|
||||
pub const STRIDE_SIZE: usize = 8;
|
||||
pub const ALU_STRIDE_SIZE: usize = 8;
|
||||
|
||||
pub const ALIGNMENT: usize = 4;
|
||||
pub const MAX_STRIDE_SIZE: usize = 8;
|
||||
|
||||
pub const ALIGNMENT_MASK: usize = 3;
|
||||
pub const ALU_ALIGNMENT: usize = 4;
|
||||
|
||||
pub const ALU_ALIGNMENT_MASK: usize = 3;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn unpack_alu(word: usize, second_word: usize, dst: *mut usize) {
|
||||
@@ -740,11 +748,13 @@ cfg_if! {
|
||||
} else if #[cfg(all(target_endian = "big", target_pointer_width = "64"))] {
|
||||
// Aligned ALU word, big-endian, 64-bit
|
||||
|
||||
pub const STRIDE_SIZE: usize = 16;
|
||||
pub const ALU_STRIDE_SIZE: usize = 16;
|
||||
|
||||
pub const ALIGNMENT: usize = 8;
|
||||
pub const MAX_STRIDE_SIZE: usize = 16;
|
||||
|
||||
pub const ALIGNMENT_MASK: usize = 7;
|
||||
pub const ALU_ALIGNMENT: usize = 8;
|
||||
|
||||
pub const ALU_ALIGNMENT_MASK: usize = 7;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn unpack_alu(word: usize, second_word: usize, dst: *mut usize) {
|
||||
@@ -794,11 +804,13 @@ cfg_if! {
|
||||
} else if #[cfg(all(target_endian = "big", target_pointer_width = "32"))] {
|
||||
// Aligned ALU word, big-endian, 32-bit
|
||||
|
||||
pub const STRIDE_SIZE: usize = 8;
|
||||
pub const ALU_STRIDE_SIZE: usize = 8;
|
||||
|
||||
pub const ALIGNMENT: usize = 4;
|
||||
pub const MAX_STRIDE_SIZE: usize = 8;
|
||||
|
||||
pub const ALIGNMENT_MASK: usize = 3;
|
||||
pub const ALU_ALIGNMENT: usize = 4;
|
||||
|
||||
pub const ALU_ALIGNMENT_MASK: usize = 3;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn unpack_alu(word: usize, second_word: usize, dst: *mut usize) {
|
||||
@@ -859,14 +871,14 @@ cfg_if! {
|
||||
let src = slice.as_ptr();
|
||||
let len = slice.len();
|
||||
let mut offset = 0usize;
|
||||
if STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
if SIMD_STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE;
|
||||
loop {
|
||||
let simd = unsafe { load16_unaligned(src.offset(offset as isize)) };
|
||||
if !simd_is_ascii(simd) {
|
||||
break;
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -887,14 +899,14 @@ cfg_if! {
|
||||
let src = slice.as_ptr();
|
||||
let len = slice.len();
|
||||
let mut offset = 0usize;
|
||||
if STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
if SIMD_STRIDE_SIZE <= len {
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE;
|
||||
// XXX Should we first process one stride unconditionally as unaligned to
|
||||
// avoid the cost of the branchiness below if the first stride fails anyway?
|
||||
// XXX Should we just use unaligned SSE2 access unconditionally? It seems that
|
||||
// on Haswell, it would make sense to just use unaligned and not bother
|
||||
// checking. Need to benchmark older architectures before deciding.
|
||||
if ((src as usize) & ALIGNMENT_MASK) == 0 {
|
||||
if ((src as usize) & SIMD_ALIGNMENT_MASK) == 0 {
|
||||
loop {
|
||||
let simd = unsafe { load16_aligned(src.offset(offset as isize)) };
|
||||
let mask = mask_ascii(simd);
|
||||
@@ -903,7 +915,7 @@ cfg_if! {
|
||||
let non_ascii = unsafe { *src.offset(offset as isize) };
|
||||
return Some((non_ascii, offset));
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -917,7 +929,7 @@ cfg_if! {
|
||||
let non_ascii = unsafe { *src.offset(offset as isize) };
|
||||
return Some((non_ascii, offset));
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -933,6 +945,93 @@ cfg_if! {
|
||||
}
|
||||
None
|
||||
}
|
||||
} else {
|
||||
#[inline(always)]
|
||||
fn find_non_ascii(word: usize, second_word: usize) -> Option<usize> {
|
||||
let word_masked = word & ASCII_MASK;
|
||||
let second_masked = second_word & ASCII_MASK;
|
||||
if (word_masked | second_masked) == 0 {
|
||||
return None;
|
||||
}
|
||||
if word_masked != 0 {
|
||||
let zeros = count_zeros(word_masked);
|
||||
// `zeros` now contains 7 (for the seven bits of non-ASCII)
|
||||
// plus 8 times the number of ASCII in text order before the
|
||||
// non-ASCII byte in the little-endian case or 8 times the number of ASCII in
|
||||
// text order before the non-ASCII byte in the big-endian case.
|
||||
let num_ascii = (zeros >> 3) as usize;
|
||||
return Some(num_ascii);
|
||||
}
|
||||
let zeros = count_zeros(second_masked);
|
||||
// `zeros` now contains 7 (for the seven bits of non-ASCII)
|
||||
// plus 8 times the number of ASCII in text order before the
|
||||
// non-ASCII byte in the little-endian case or 8 times the number of ASCII in
|
||||
// text order before the non-ASCII byte in the big-endian case.
|
||||
let num_ascii = (zeros >> 3) as usize;
|
||||
Some(ALU_ALIGNMENT + num_ascii)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn validate_ascii_stride(src: *const usize) -> Option<usize> {
|
||||
let word = *src;
|
||||
let second_word = *(src.offset(1));
|
||||
find_non_ascii(word, second_word)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn validate_ascii(slice: &[u8]) -> Option<(u8, usize)> {
|
||||
let src = slice.as_ptr();
|
||||
let len = slice.len();
|
||||
let mut offset = 0usize;
|
||||
let mut until_alignment = (ALU_ALIGNMENT - ((src as usize) & ALU_ALIGNMENT_MASK)) & ALU_ALIGNMENT_MASK;
|
||||
if until_alignment + ALU_STRIDE_SIZE <= len {
|
||||
while until_alignment != 0 {
|
||||
let code_unit = slice[offset];
|
||||
if code_unit > 127 {
|
||||
return Some((code_unit, offset));
|
||||
}
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - ALU_STRIDE_SIZE;
|
||||
loop {
|
||||
let ptr = unsafe { src.offset(offset as isize) as *const usize };
|
||||
if let Some(num_ascii) = unsafe { validate_ascii_stride(ptr) } {
|
||||
offset += num_ascii;
|
||||
return Some((unsafe { *(src.offset(offset as isize)) }, offset));
|
||||
}
|
||||
offset += ALU_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while offset < len {
|
||||
let code_unit = slice[offset];
|
||||
if code_unit > 127 {
|
||||
return Some((code_unit, offset));
|
||||
}
|
||||
offset += 1;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"))))] {
|
||||
|
||||
} else if #[cfg(all(feature = "simd-accel", target_endian = "little", target_feature = "neon"))] {
|
||||
// Even with NEON enabled, we use the ALU path for ASCII validation, because testing
|
||||
// on Exynos 5 indicated that using NEON isn't worthwhile where there are only
|
||||
// vector reads without vector writes.
|
||||
|
||||
pub const ALU_STRIDE_SIZE: usize = 8;
|
||||
|
||||
pub const ALU_ALIGNMENT: usize = 4;
|
||||
|
||||
pub const ALU_ALIGNMENT_MASK: usize = 3;
|
||||
} else {
|
||||
#[inline(always)]
|
||||
unsafe fn unpack_latin1_stride_alu(src: *const usize, dst: *mut usize) {
|
||||
@@ -975,11 +1074,6 @@ cfg_if! {
|
||||
true
|
||||
}
|
||||
|
||||
basic_latin_alu!(ascii_to_basic_latin, u8, u16, ascii_to_basic_latin_stride_alu);
|
||||
basic_latin_alu!(basic_latin_to_ascii, u16, u8, basic_latin_to_ascii_stride_alu);
|
||||
latin1_alu!(unpack_latin1, u8, u16, unpack_latin1_stride_alu);
|
||||
latin1_alu!(pack_latin1, u16, u8, pack_latin1_stride_alu);
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn ascii_to_ascii_stride(src: *const usize, dst: *mut usize) -> Option<usize> {
|
||||
let word = *src;
|
||||
@@ -989,82 +1083,15 @@ cfg_if! {
|
||||
find_non_ascii(word, second_word)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn validate_ascii_stride(src: *const usize) -> Option<usize> {
|
||||
let word = *src;
|
||||
let second_word = *(src.offset(1));
|
||||
find_non_ascii(word, second_word)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn find_non_ascii(word: usize, second_word: usize) -> Option<usize> {
|
||||
let word_masked = word & ASCII_MASK;
|
||||
let second_masked = second_word & ASCII_MASK;
|
||||
if (word_masked | second_masked) == 0 {
|
||||
return None;
|
||||
}
|
||||
if word_masked != 0 {
|
||||
let zeros = count_zeros(word_masked);
|
||||
// `zeros` now contains 7 (for the seven bits of non-ASCII)
|
||||
// plus 8 times the number of ASCII in text order before the
|
||||
// non-ASCII byte in the little-endian case or 8 times the number of ASCII in
|
||||
// text order before the non-ASCII byte in the big-endian case.
|
||||
let num_ascii = (zeros >> 3) as usize;
|
||||
return Some(num_ascii);
|
||||
}
|
||||
let zeros = count_zeros(second_masked);
|
||||
// `zeros` now contains 7 (for the seven bits of non-ASCII)
|
||||
// plus 8 times the number of ASCII in text order before the
|
||||
// non-ASCII byte in the little-endian case or 8 times the number of ASCII in
|
||||
// text order before the non-ASCII byte in the big-endian case.
|
||||
let num_ascii = (zeros >> 3) as usize;
|
||||
Some(ALIGNMENT + num_ascii)
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "simd-accel", target_endian = "little", target_arch = "aarch64")))]
|
||||
basic_latin_alu!(ascii_to_basic_latin, u8, u16, ascii_to_basic_latin_stride_alu);
|
||||
basic_latin_alu!(basic_latin_to_ascii, u16, u8, basic_latin_to_ascii_stride_alu);
|
||||
latin1_alu!(unpack_latin1, u8, u16, unpack_latin1_stride_alu);
|
||||
latin1_alu!(pack_latin1, u16, u8, pack_latin1_stride_alu);
|
||||
ascii_alu!(ascii_to_ascii, u8, u8, ascii_to_ascii_stride);
|
||||
|
||||
#[inline(always)]
|
||||
pub fn validate_ascii(slice: &[u8]) -> Option<(u8, usize)> {
|
||||
let src = slice.as_ptr();
|
||||
let len = slice.len();
|
||||
let mut offset = 0usize;
|
||||
let mut until_alignment = (ALIGNMENT - ((src as usize) & ALIGNMENT_MASK)) & ALIGNMENT_MASK;
|
||||
if until_alignment + STRIDE_SIZE <= len {
|
||||
while until_alignment != 0 {
|
||||
let code_unit = slice[offset];
|
||||
if code_unit > 127 {
|
||||
return Some((code_unit, offset));
|
||||
}
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
loop {
|
||||
let ptr = unsafe { src.offset(offset as isize) as *const usize };
|
||||
if let Some(num_ascii) = unsafe { validate_ascii_stride(ptr) } {
|
||||
offset += num_ascii;
|
||||
return Some((unsafe { *(src.offset(offset as isize)) }, offset));
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while offset < len {
|
||||
let code_unit = slice[offset];
|
||||
if code_unit > 127 {
|
||||
return Some((code_unit, offset));
|
||||
}
|
||||
offset += 1;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn ascii_valid_up_to(bytes: &[u8]) -> usize {
|
||||
match validate_ascii(bytes) {
|
||||
None => bytes.len(),
|
||||
|
||||
+6
-6
@@ -643,7 +643,7 @@
|
||||
extern crate cfg_if;
|
||||
|
||||
#[cfg(all(feature = "simd-accel",
|
||||
any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"))))]
|
||||
any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"), all(target_endian = "little", target_feature = "neon"))))]
|
||||
extern crate simd;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
@@ -661,7 +661,7 @@ extern crate serde_json;
|
||||
mod macros;
|
||||
|
||||
#[cfg(all(feature = "simd-accel",
|
||||
any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"))))]
|
||||
any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"), all(target_endian = "little", target_feature = "neon"))))]
|
||||
mod simd_funcs;
|
||||
|
||||
#[cfg(any(all(feature = "simd-accel", target_feature = "sse2"),
|
||||
@@ -3482,11 +3482,11 @@ impl Decoder {
|
||||
let (result, read, written, replaced) = self.decode_to_utf8(src, bytes, last);
|
||||
let len = bytes.len();
|
||||
let mut trail = written;
|
||||
// Non-UTF-8 ASCII-compatible decoders may write up to `STRIDE_SIZE`
|
||||
// Non-UTF-8 ASCII-compatible decoders may write up to `MAX_STRIDE_SIZE`
|
||||
// bytes of trailing garbage. No need to optimize non-ASCII-compatible
|
||||
// encodings to avoid overwriting here.
|
||||
if self.encoding != UTF_8 {
|
||||
let max = std::cmp::min(len, trail + ascii::STRIDE_SIZE);
|
||||
let max = std::cmp::min(len, trail + ascii::MAX_STRIDE_SIZE);
|
||||
while trail < max {
|
||||
bytes[trail] = 0;
|
||||
trail += 1;
|
||||
@@ -3572,11 +3572,11 @@ impl Decoder {
|
||||
let (result, read, written) = self.decode_to_utf8_without_replacement(src, bytes, last);
|
||||
let len = bytes.len();
|
||||
let mut trail = written;
|
||||
// Non-UTF-8 ASCII-compatible decoders may write up to `STRIDE_SIZE`
|
||||
// Non-UTF-8 ASCII-compatible decoders may write up to `MAX_STRIDE_SIZE`
|
||||
// bytes of trailing garbage. No need to optimize non-ASCII-compatible
|
||||
// encodings to avoid overwriting here.
|
||||
if self.encoding != UTF_8 {
|
||||
let max = std::cmp::min(len, trail + ascii::STRIDE_SIZE);
|
||||
let max = std::cmp::min(len, trail + ascii::MAX_STRIDE_SIZE);
|
||||
while trail < max {
|
||||
bytes[trail] = 0;
|
||||
trail += 1;
|
||||
|
||||
+52
-52
@@ -75,16 +75,16 @@ macro_rules! by_unit_check_alu {
|
||||
let mut accu = 0usize;
|
||||
let unit_size = ::std::mem::size_of::<$unit>();
|
||||
let len = buffer.len();
|
||||
if len >= ALIGNMENT / unit_size {
|
||||
if len >= ALU_ALIGNMENT / unit_size {
|
||||
// The most common reason to return `false` is for the first code
|
||||
// unit to fail the test, so check that first.
|
||||
if buffer[0] >= $bound {
|
||||
return false;
|
||||
}
|
||||
let src = buffer.as_ptr();
|
||||
let mut until_alignment = ((ALIGNMENT - ((src as usize) & ALIGNMENT_MASK)) &
|
||||
ALIGNMENT_MASK) / unit_size;
|
||||
if until_alignment + ALIGNMENT / unit_size <= len {
|
||||
let mut until_alignment = ((ALU_ALIGNMENT - ((src as usize) & ALU_ALIGNMENT_MASK)) &
|
||||
ALU_ALIGNMENT_MASK) / unit_size;
|
||||
if until_alignment + ALU_ALIGNMENT / unit_size <= len {
|
||||
if until_alignment != 0 {
|
||||
accu |= buffer[offset] as usize;
|
||||
offset += 1;
|
||||
@@ -98,18 +98,18 @@ macro_rules! by_unit_check_alu {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let len_minus_stride = len - ALIGNMENT / unit_size;
|
||||
if offset + (4 * (ALIGNMENT / unit_size)) <= len {
|
||||
let len_minus_unroll = len - (4 * (ALIGNMENT / unit_size));
|
||||
let len_minus_stride = len - ALU_ALIGNMENT / unit_size;
|
||||
if offset + (4 * (ALU_ALIGNMENT / unit_size)) <= len {
|
||||
let len_minus_unroll = len - (4 * (ALU_ALIGNMENT / unit_size));
|
||||
loop {
|
||||
let unroll_accu = unsafe { *(src.offset(offset as isize) as *const usize) } |
|
||||
unsafe { *(src.offset((offset + (ALIGNMENT / unit_size)) as isize) as *const usize) } |
|
||||
unsafe { *(src.offset((offset + (2 * (ALIGNMENT / unit_size))) as isize) as *const usize) } |
|
||||
unsafe { *(src.offset((offset + (3 * (ALIGNMENT / unit_size))) as isize) as *const usize) };
|
||||
unsafe { *(src.offset((offset + (ALU_ALIGNMENT / unit_size)) as isize) as *const usize) } |
|
||||
unsafe { *(src.offset((offset + (2 * (ALU_ALIGNMENT / unit_size))) as isize) as *const usize) } |
|
||||
unsafe { *(src.offset((offset + (3 * (ALU_ALIGNMENT / unit_size))) as isize) as *const usize) };
|
||||
if unroll_accu & $mask != 0 {
|
||||
return false;
|
||||
}
|
||||
offset += 4 * (ALIGNMENT / unit_size);
|
||||
offset += 4 * (ALU_ALIGNMENT / unit_size);
|
||||
if offset > len_minus_unroll {
|
||||
break;
|
||||
}
|
||||
@@ -117,7 +117,7 @@ macro_rules! by_unit_check_alu {
|
||||
}
|
||||
while offset <= len_minus_stride {
|
||||
accu |= unsafe { *(src.offset(offset as isize) as *const usize) };
|
||||
offset += ALIGNMENT / unit_size;
|
||||
offset += ALU_ALIGNMENT / unit_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ macro_rules! by_unit_check_simd {
|
||||
let mut accu = 0usize;
|
||||
let unit_size = ::std::mem::size_of::<$unit>();
|
||||
let len = buffer.len();
|
||||
if len >= STRIDE_SIZE / unit_size {
|
||||
if len >= SIMD_STRIDE_SIZE / unit_size {
|
||||
// The most common reason to return `false` is for the first code
|
||||
// unit to fail the test, so check that first.
|
||||
if buffer[0] >= $bound {
|
||||
@@ -151,7 +151,7 @@ macro_rules! by_unit_check_simd {
|
||||
let src = buffer.as_ptr();
|
||||
let mut until_alignment = ((SIMD_ALIGNMENT - ((src as usize) & SIMD_ALIGNMENT_MASK)) &
|
||||
SIMD_ALIGNMENT_MASK) / unit_size;
|
||||
if until_alignment + STRIDE_SIZE / unit_size <= len {
|
||||
if until_alignment + SIMD_STRIDE_SIZE / unit_size <= len {
|
||||
if until_alignment != 0 {
|
||||
accu |= buffer[offset] as usize;
|
||||
offset += 1;
|
||||
@@ -165,18 +165,18 @@ macro_rules! by_unit_check_simd {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let len_minus_stride = len - STRIDE_SIZE / unit_size;
|
||||
if offset + (4 * (STRIDE_SIZE / unit_size)) <= len {
|
||||
let len_minus_unroll = len - (4 * (STRIDE_SIZE / unit_size));
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE / unit_size;
|
||||
if offset + (4 * (SIMD_STRIDE_SIZE / unit_size)) <= len {
|
||||
let len_minus_unroll = len - (4 * (SIMD_STRIDE_SIZE / unit_size));
|
||||
loop {
|
||||
let unroll_accu = unsafe { *(src.offset(offset as isize) as *const $simd_ty) } |
|
||||
unsafe { *(src.offset((offset + (STRIDE_SIZE / unit_size)) as isize) as *const $simd_ty) } |
|
||||
unsafe { *(src.offset((offset + (2 * (STRIDE_SIZE / unit_size))) as isize) as *const $simd_ty) } |
|
||||
unsafe { *(src.offset((offset + (3 * (STRIDE_SIZE / unit_size))) as isize) as *const $simd_ty) };
|
||||
unsafe { *(src.offset((offset + (SIMD_STRIDE_SIZE / unit_size)) as isize) as *const $simd_ty) } |
|
||||
unsafe { *(src.offset((offset + (2 * (SIMD_STRIDE_SIZE / unit_size))) as isize) as *const $simd_ty) } |
|
||||
unsafe { *(src.offset((offset + (3 * (SIMD_STRIDE_SIZE / unit_size))) as isize) as *const $simd_ty) };
|
||||
if !$func(unroll_accu) {
|
||||
return false;
|
||||
}
|
||||
offset += 4 * (STRIDE_SIZE / unit_size);
|
||||
offset += 4 * (SIMD_STRIDE_SIZE / unit_size);
|
||||
if offset > len_minus_unroll {
|
||||
break;
|
||||
}
|
||||
@@ -185,7 +185,7 @@ macro_rules! by_unit_check_simd {
|
||||
let mut simd_accu = $splat;
|
||||
while offset <= len_minus_stride {
|
||||
simd_accu = simd_accu | unsafe { *(src.offset(offset as isize) as *const $simd_ty) };
|
||||
offset += STRIDE_SIZE / unit_size;
|
||||
offset += SIMD_STRIDE_SIZE / unit_size;
|
||||
}
|
||||
if !$func(simd_accu) {
|
||||
return false;
|
||||
@@ -200,7 +200,7 @@ macro_rules! by_unit_check_simd {
|
||||
}
|
||||
|
||||
cfg_if!{
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"))))] {
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"), all(target_endian = "little", target_feature = "neon"))))] {
|
||||
use simd_funcs::*;
|
||||
use simd::u8x16;
|
||||
use simd::u16x8;
|
||||
@@ -227,13 +227,13 @@ cfg_if!{
|
||||
let until_alignment = ((SIMD_ALIGNMENT - ((unsafe { src.offset(offset as isize) } as usize) & SIMD_ALIGNMENT_MASK)) &
|
||||
SIMD_ALIGNMENT_MASK) / unit_size;
|
||||
if until_alignment == 0 {
|
||||
if offset + STRIDE_SIZE / unit_size > len {
|
||||
if offset + SIMD_STRIDE_SIZE / unit_size > len {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
let offset_plus_until_alignment = offset + until_alignment;
|
||||
let offset_plus_until_alignment_plus_one = offset_plus_until_alignment + 1;
|
||||
if offset_plus_until_alignment_plus_one + STRIDE_SIZE / unit_size > len {
|
||||
if offset_plus_until_alignment_plus_one + SIMD_STRIDE_SIZE / unit_size > len {
|
||||
break;
|
||||
}
|
||||
let (up_to, last_valid_low) = utf16_valid_up_to_alu(&buffer[offset..offset_plus_until_alignment_plus_one]);
|
||||
@@ -246,16 +246,16 @@ cfg_if!{
|
||||
}
|
||||
offset = offset_plus_until_alignment;
|
||||
}
|
||||
let len_minus_stride = len - STRIDE_SIZE / unit_size;
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE / unit_size;
|
||||
'inner: loop {
|
||||
let offset_plus_stride = offset + STRIDE_SIZE / unit_size;
|
||||
let offset_plus_stride = offset + SIMD_STRIDE_SIZE / unit_size;
|
||||
if contains_surrogates(unsafe { *(src.offset(offset as isize) as *const u16x8) }) {
|
||||
if offset_plus_stride == len {
|
||||
break 'outer;
|
||||
}
|
||||
let offset_plus_stride_plus_one = offset_plus_stride + 1;
|
||||
let (up_to, last_valid_low) = utf16_valid_up_to_alu(&buffer[offset..offset_plus_stride_plus_one]);
|
||||
if up_to < STRIDE_SIZE / unit_size {
|
||||
if up_to < SIMD_STRIDE_SIZE / unit_size {
|
||||
return offset + up_to;
|
||||
}
|
||||
if last_valid_low {
|
||||
@@ -331,17 +331,17 @@ fn utf16_valid_up_to_alu(buffer: &[u16]) -> (usize, bool) {
|
||||
}
|
||||
|
||||
cfg_if!{
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"))))] {
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"), all(target_endian = "little", target_feature = "neon"))))] {
|
||||
#[inline(always)]
|
||||
fn is_str_latin1_impl(buffer: &str) -> Option<usize> {
|
||||
let mut offset = 0usize;
|
||||
let bytes = buffer.as_bytes();
|
||||
let len = bytes.len();
|
||||
if len >= STRIDE_SIZE {
|
||||
if len >= SIMD_STRIDE_SIZE {
|
||||
let src = bytes.as_ptr();
|
||||
let mut until_alignment = (SIMD_ALIGNMENT - ((src as usize) & SIMD_ALIGNMENT_MASK)) &
|
||||
SIMD_ALIGNMENT_MASK;
|
||||
if until_alignment + STRIDE_SIZE <= len {
|
||||
if until_alignment + SIMD_STRIDE_SIZE <= len {
|
||||
while until_alignment != 0 {
|
||||
if bytes[offset] > 0xC3 {
|
||||
return Some(offset);
|
||||
@@ -349,7 +349,7 @@ cfg_if!{
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - STRIDE_SIZE;
|
||||
let len_minus_stride = len - SIMD_STRIDE_SIZE;
|
||||
loop {
|
||||
if !simd_is_str_latin1(unsafe { *(src.offset(offset as isize) as *const u8x16) }) {
|
||||
// TODO: Ensure this compiles away when inlined into `is_str_latin1()`.
|
||||
@@ -358,7 +358,7 @@ cfg_if!{
|
||||
}
|
||||
return Some(offset);
|
||||
}
|
||||
offset += STRIDE_SIZE;
|
||||
offset += SIMD_STRIDE_SIZE;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -420,16 +420,16 @@ fn is_utf8_latin1_impl(buffer: &[u8]) -> Option<usize> {
|
||||
}
|
||||
|
||||
cfg_if!{
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"))))] {
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"), all(target_endian = "little", target_feature = "neon"))))] {
|
||||
#[inline(always)]
|
||||
fn is_utf16_bidi_impl(buffer: &[u16]) -> bool {
|
||||
let mut offset = 0usize;
|
||||
let len = buffer.len();
|
||||
if len >= STRIDE_SIZE / 2 {
|
||||
if len >= SIMD_STRIDE_SIZE / 2 {
|
||||
let src = buffer.as_ptr();
|
||||
let mut until_alignment = ((SIMD_ALIGNMENT - ((src as usize) & SIMD_ALIGNMENT_MASK)) &
|
||||
SIMD_ALIGNMENT_MASK) / 2;
|
||||
if until_alignment + (STRIDE_SIZE / 2) <= len {
|
||||
if until_alignment + (SIMD_STRIDE_SIZE / 2) <= len {
|
||||
while until_alignment != 0 {
|
||||
if is_utf16_code_unit_bidi(buffer[offset]) {
|
||||
return true;
|
||||
@@ -437,12 +437,12 @@ cfg_if!{
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - (STRIDE_SIZE / 2);
|
||||
let len_minus_stride = len - (SIMD_STRIDE_SIZE / 2);
|
||||
loop {
|
||||
if is_u16x8_bidi(unsafe { *(src.offset(offset as isize) as *const u16x8) }) {
|
||||
return true;
|
||||
}
|
||||
offset += STRIDE_SIZE / 2;
|
||||
offset += SIMD_STRIDE_SIZE / 2;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -470,16 +470,16 @@ cfg_if!{
|
||||
}
|
||||
|
||||
cfg_if!{
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"))))] {
|
||||
if #[cfg(all(feature = "simd-accel", any(target_feature = "sse2", all(target_endian = "little", target_arch = "aarch64"), all(target_endian = "little", target_feature = "neon"))))] {
|
||||
#[inline(always)]
|
||||
fn check_utf16_for_latin1_and_bidi_impl(buffer: &[u16]) -> Latin1Bidi {
|
||||
let mut offset = 0usize;
|
||||
let len = buffer.len();
|
||||
if len >= STRIDE_SIZE / 2 {
|
||||
if len >= SIMD_STRIDE_SIZE / 2 {
|
||||
let src = buffer.as_ptr();
|
||||
let mut until_alignment = ((SIMD_ALIGNMENT - ((src as usize) & SIMD_ALIGNMENT_MASK)) &
|
||||
SIMD_ALIGNMENT_MASK) / 2;
|
||||
if until_alignment + (STRIDE_SIZE / 2) <= len {
|
||||
if until_alignment + (SIMD_STRIDE_SIZE / 2) <= len {
|
||||
while until_alignment != 0 {
|
||||
if buffer[offset] > 0xFF {
|
||||
// This transition isn't optimal, since the aligment is recomputing
|
||||
@@ -492,7 +492,7 @@ cfg_if!{
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - (STRIDE_SIZE / 2);
|
||||
let len_minus_stride = len - (SIMD_STRIDE_SIZE / 2);
|
||||
loop {
|
||||
let mut s = unsafe { *(src.offset(offset as isize) as *const u16x8) };
|
||||
if !simd_is_latin1(s) {
|
||||
@@ -500,7 +500,7 @@ cfg_if!{
|
||||
if is_u16x8_bidi(s) {
|
||||
return Latin1Bidi::Bidi;
|
||||
}
|
||||
offset += STRIDE_SIZE / 2;
|
||||
offset += SIMD_STRIDE_SIZE / 2;
|
||||
if offset > len_minus_stride {
|
||||
for &u in &buffer[offset..] {
|
||||
if is_utf16_code_unit_bidi(u) {
|
||||
@@ -512,7 +512,7 @@ cfg_if!{
|
||||
s = unsafe { *(src.offset(offset as isize) as *const u16x8) };
|
||||
}
|
||||
}
|
||||
offset += STRIDE_SIZE / 2;
|
||||
offset += SIMD_STRIDE_SIZE / 2;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -545,11 +545,11 @@ cfg_if!{
|
||||
fn check_utf16_for_latin1_and_bidi_impl(buffer: &[u16]) -> Latin1Bidi {
|
||||
let mut offset = 0usize;
|
||||
let len = buffer.len();
|
||||
if len >= ALIGNMENT / 2 {
|
||||
if len >= ALU_ALIGNMENT / 2 {
|
||||
let src = buffer.as_ptr();
|
||||
let mut until_alignment = ((ALIGNMENT - ((src as usize) & ALIGNMENT_MASK)) &
|
||||
ALIGNMENT_MASK) / 2;
|
||||
if until_alignment + ALIGNMENT / 2 <= len {
|
||||
let mut until_alignment = ((ALU_ALIGNMENT - ((src as usize) & ALU_ALIGNMENT_MASK)) &
|
||||
ALU_ALIGNMENT_MASK) / 2;
|
||||
if until_alignment + ALU_ALIGNMENT / 2 <= len {
|
||||
while until_alignment != 0 {
|
||||
if buffer[offset] > 0xFF {
|
||||
if is_utf16_bidi_impl(&buffer[offset..]) {
|
||||
@@ -560,7 +560,7 @@ cfg_if!{
|
||||
offset += 1;
|
||||
until_alignment -= 1;
|
||||
}
|
||||
let len_minus_stride = len - ALIGNMENT / 2;
|
||||
let len_minus_stride = len - ALU_ALIGNMENT / 2;
|
||||
loop {
|
||||
if unsafe { *(src.offset(offset as isize) as *const usize) } & LATIN1_MASK != 0 {
|
||||
if is_utf16_bidi_impl(&buffer[offset..]) {
|
||||
@@ -568,7 +568,7 @@ cfg_if!{
|
||||
}
|
||||
return Latin1Bidi::LeftToRight;
|
||||
}
|
||||
offset += ALIGNMENT / 2;
|
||||
offset += ALU_ALIGNMENT / 2;
|
||||
if offset > len_minus_stride {
|
||||
break;
|
||||
}
|
||||
@@ -1575,7 +1575,7 @@ pub fn convert_utf16_to_str(src: &[u16], dst: &mut str) -> usize {
|
||||
let written = convert_utf16_to_utf8(src, bytes);
|
||||
let len = bytes.len();
|
||||
let mut trail = written;
|
||||
let max = ::std::cmp::min(len, trail + STRIDE_SIZE);
|
||||
let max = ::std::cmp::min(len, trail + MAX_STRIDE_SIZE);
|
||||
while trail < max {
|
||||
bytes[trail] = 0;
|
||||
trail += 1;
|
||||
@@ -1683,7 +1683,7 @@ pub fn convert_latin1_to_str(src: &[u8], dst: &mut str) -> usize {
|
||||
let written = convert_latin1_to_utf8(src, bytes);
|
||||
let len = bytes.len();
|
||||
let mut trail = written;
|
||||
let max = ::std::cmp::min(len, trail + STRIDE_SIZE);
|
||||
let max = ::std::cmp::min(len, trail + MAX_STRIDE_SIZE);
|
||||
while trail < max {
|
||||
bytes[trail] = 0;
|
||||
trail += 1;
|
||||
|
||||
+4
-2
@@ -113,8 +113,10 @@ cfg_if! {
|
||||
} else {
|
||||
#[inline(always)]
|
||||
pub fn simd_is_ascii(s: u8x16) -> bool {
|
||||
let above_ascii = u8x16::splat(0x80);
|
||||
s.lt(above_ascii).all()
|
||||
// This optimizes better on ARM than
|
||||
// the lt formulation.
|
||||
let highest_ascii = u8x16::splat(0x7F);
|
||||
!s.gt(highest_ascii).any()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user