diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06283d5..0a7cab2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,6 @@ on: branches: [master] pull_request: workflow_dispatch: - schedule: [cron: "40 1 * * *"] permissions: contents: read @@ -15,28 +14,44 @@ env: jobs: test: - name: Test + name: Test +${{ matrix.rust }} ${{ matrix.target.triple }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: - target: [aarch64-unknown-linux-gnu, i686-unknown-linux-gnu, x86_64-unknown-linux-gnu] + target: + - triple: aarch64-unknown-linux-gnu + feature: +neon + - triple: i686-unknown-linux-gnu + feature: +avx2 + - triple: x86_64-unknown-linux-gnu + feature: +avx2 + - triple: wasm32-wasip1 + feature: +simd128 rust: [nightly, stable, 1.64] + exclude: + - target: + triple: wasm32-wasip1 + feature: +simd128 + rust: 1.64 timeout-minutes: 30 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - target: ${{ matrix.target }} + target: ${{ matrix.target.triple }} - uses: taiki-e/setup-cross-toolchain-action@v1 with: - target: ${{ matrix.target }} + target: ${{ matrix.target.triple }} - name: Enable type layout randomization run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV if: matrix.rust == 'nightly' + - name: Enable target feature + run: echo RUSTFLAGS=${RUSTFLAGS}\ -Ctarget-feature=${{ matrix.target.feature }} >> $GITHUB_ENV + - uses: Swatinem/rust-cache@v2 - run: cargo build diff --git a/src/arch/aarch64.rs b/src/arch/aarch64.rs index a04bad5..b381b0c 100644 --- a/src/arch/aarch64.rs +++ b/src/arch/aarch64.rs @@ -80,7 +80,7 @@ pub(crate) unsafe fn check_neon(input: &[u8]) -> bool { let ascii_la = vdupq_n_u8(b'a' - 1); let ascii_lf = vdupq_n_u8(b'f' + 1); - generic::check_unaligned_chunks(input, |chunk| { + generic::check_unaligned_chunks(input, |chunk: uint8x16_t| { let ge0 = vcgtq_u8(chunk, ascii_zero); let le9 = vcltq_u8(chunk, ascii_nine); let valid_digit = vandq_u8(ge0, le9); diff --git a/src/arch/mod.rs b/src/arch/mod.rs index e614e3c..e223620 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -13,6 +13,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_arch = "aarch64")] { pub(crate) mod aarch64; pub(crate) use aarch64 as imp; + } else if #[cfg(target_arch = "wasm32")] { + pub(crate) mod wasm32; + pub(crate) use wasm32 as imp; } else { pub(crate) use generic as imp; } diff --git a/src/arch/portable_simd.rs b/src/arch/portable_simd.rs index 64bd040..4f2b907 100644 --- a/src/arch/portable_simd.rs +++ b/src/arch/portable_simd.rs @@ -44,7 +44,7 @@ pub(crate) unsafe fn encode(input: &[u8], output: *mut u8) { } pub(crate) fn check(input: &[u8]) -> bool { - generic::check_unaligned_chunks::(input, |chunk| { + generic::check_unaligned_chunks(input, |chunk: Simd| { let valid_digit = chunk.simd_ge(Simd::splat(b'0')) & chunk.simd_le(Simd::splat(b'9')); let valid_upper = chunk.simd_ge(Simd::splat(b'A')) & chunk.simd_le(Simd::splat(b'F')); let valid_lower = chunk.simd_ge(Simd::splat(b'a')) & chunk.simd_le(Simd::splat(b'f')); diff --git a/src/arch/wasm32.rs b/src/arch/wasm32.rs new file mode 100644 index 0000000..b3107c8 --- /dev/null +++ b/src/arch/wasm32.rs @@ -0,0 +1,40 @@ +use super::generic; +use core::arch::wasm32::*; + +pub(crate) const USE_CHECK_FN: bool = false; + +pub(crate) use generic::{decode_checked, decode_unchecked, encode}; + +#[inline(always)] +fn is_available() -> bool { + cfg!(target_feature = "simd128") +} + +#[inline] +pub(crate) fn check(input: &[u8]) -> bool { + if !is_available() { + return generic::check(input); + } + unsafe { check_simd128(input) } +} + +#[target_feature(enable = "simd128")] +unsafe fn check_simd128(input: &[u8]) -> bool { + generic::check_unaligned_chunks(input, |chunk: v128| { + let ge0 = u8x16_ge(chunk, u8x16_splat(b'0')); + let le9 = u8x16_le(chunk, u8x16_splat(b'9')); + let valid_digit = v128_and(ge0, le9); + + let geua = u8x16_ge(chunk, u8x16_splat(b'A')); + let leuf = u8x16_le(chunk, u8x16_splat(b'F')); + let valid_upper = v128_and(geua, leuf); + + let gela = u8x16_ge(chunk, u8x16_splat(b'a')); + let lelf = u8x16_le(chunk, u8x16_splat(b'f')); + let valid_lower = v128_and(gela, lelf); + + let valid_letter = v128_or(valid_lower, valid_upper); + let valid = v128_or(valid_digit, valid_letter); + u8x16_all_true(valid) + }) +} diff --git a/src/arch/x86.rs b/src/arch/x86.rs index bdf5082..1029dcf 100644 --- a/src/arch/x86.rs +++ b/src/arch/x86.rs @@ -99,7 +99,7 @@ unsafe fn check_sse2(input: &[u8]) -> bool { let ascii_la = _mm_set1_epi8((b'a' - 1) as i8); let ascii_lf = _mm_set1_epi8((b'f' + 1) as i8); - generic::check_unaligned_chunks(input, |chunk| { + generic::check_unaligned_chunks(input, |chunk: __m128i| { let ge0 = _mm_cmpgt_epi8(chunk, ascii_zero); let le9 = _mm_cmplt_epi8(chunk, ascii_nine); let valid_digit = _mm_and_si128(ge0, le9);