const_hex/arch/
aarch64.rs

1#![allow(unsafe_op_in_unsafe_fn)]
2
3use super::generic;
4use crate::get_chars_table;
5use core::arch::aarch64::*;
6
7pub(crate) const USE_CHECK_FN: bool = true;
8
9cfg_if::cfg_if! {
10    if #[cfg(feature = "std")] {
11        #[inline(always)]
12        fn has_neon() -> bool {
13            std::arch::is_aarch64_feature_detected!("neon")
14        }
15    } else {
16        #[inline(always)]
17        fn has_neon() -> bool {
18            cfg!(target_feature = "neon")
19        }
20    }
21}
22
23#[inline]
24pub(crate) unsafe fn encode<const UPPER: bool>(input: &[u8], output: *mut u8) {
25    if cfg!(miri) || !has_neon() {
26        return generic::encode::<UPPER>(input, output);
27    }
28    encode_neon::<UPPER>(input, output);
29}
30
31#[target_feature(enable = "neon")]
32pub(crate) unsafe fn encode_neon<const UPPER: bool>(input: &[u8], output: *mut u8) {
33    // Load table.
34    let hex_table = vld1q_u8(get_chars_table::<UPPER>().as_ptr());
35
36    generic::encode_unaligned_chunks::<UPPER, _>(input, output, |chunk: uint8x16_t| {
37        // Load input bytes and mask to nibbles.
38        let mut lo = vandq_u8(chunk, vdupq_n_u8(0x0F));
39        let mut hi = vshrq_n_u8(chunk, 4);
40
41        // Lookup the corresponding ASCII hex digit for each nibble.
42        lo = vqtbl1q_u8(hex_table, lo);
43        hi = vqtbl1q_u8(hex_table, hi);
44
45        // Interleave the nibbles ([hi[0], lo[0], hi[1], lo[1], ...]).
46        let hex_lo = vzip1q_u8(hi, lo);
47        let hex_hi = vzip2q_u8(hi, lo);
48        (hex_lo, hex_hi)
49    });
50}
51
52#[inline]
53pub(crate) fn check(input: &[u8]) -> bool {
54    if cfg!(miri) || !has_neon() {
55        return generic::check(input);
56    }
57    unsafe { check_neon(input) }
58}
59
60#[target_feature(enable = "neon")]
61pub(crate) unsafe fn check_neon(input: &[u8]) -> bool {
62    generic::check_unaligned_chunks(input, |chunk: uint8x16_t| {
63        let ge0 = vcgeq_u8(chunk, vdupq_n_u8(b'0'));
64        let le9 = vcleq_u8(chunk, vdupq_n_u8(b'9'));
65        let valid_digit = vandq_u8(ge0, le9);
66
67        let geua = vcgeq_u8(chunk, vdupq_n_u8(b'A'));
68        let leuf = vcleq_u8(chunk, vdupq_n_u8(b'F'));
69        let valid_upper = vandq_u8(geua, leuf);
70
71        let gela = vcgeq_u8(chunk, vdupq_n_u8(b'a'));
72        let lelf = vcleq_u8(chunk, vdupq_n_u8(b'f'));
73        let valid_lower = vandq_u8(gela, lelf);
74
75        let valid_letter = vorrq_u8(valid_lower, valid_upper);
76        let valid_mask = vorrq_u8(valid_digit, valid_letter);
77        vminvq_u8(valid_mask) == 0xFF
78    })
79}
80
81pub(crate) use generic::decode_checked;
82pub(crate) use generic::decode_unchecked;