Skip to content

Commit 1e4b8a8

Browse files
committed
wasm32: require 'simd128' to be enabled at compile time
It turns out that providing routines with `#[target_feature(enable = "simd128")]` on `wasm32` can fail in some older browsers. The specific problem is not totally clear to me, but it is straight-forward enough to fix (I hope) by just requiring that `simd128` be enabled at compile time in order to include the `wasm32` SIMD modules in this crate. This would not be a great solution if WASM supported runtime CPU feature detection. And the status quo is that `simd128` has to be enabled at compile time anyway for the SIMD code to take effect. So this shouldn't cause any regressions and is likely something we can do long term as well. We can re-evaluate once and if WASM gets support for runtime CPU feature detection. We also add a CI test for `wasm32` *without* the `simd128` target feature enabled. Fixes #144
1 parent e02697b commit 1e4b8a8

File tree

8 files changed

+73
-54
lines changed

8 files changed

+73
-54
lines changed

.github/workflows/ci.yml

+34-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,40 @@ jobs:
152152
curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v$WASMTIME_VERSION/wasmtime-v$WASMTIME_VERSION-x86_64-linux.tar.xz
153153
tar xvf wasmtime-v$WASMTIME_VERSION-x86_64-linux.tar.xz
154154
echo `pwd`/wasmtime-v$WASMTIME_VERSION-x86_64-linux >> $GITHUB_PATH
155-
echo "CARGO_TARGET_WASM32_WASI_RUNNER=wasmtime run --wasm-features simd --" >> $GITHUB_ENV
155+
echo "CARGO_TARGET_WASM32_WASI_RUNNER=wasmtime run --wasm simd --" >> $GITHUB_ENV
156+
- name: Basic build
157+
run: cargo build --verbose
158+
- name: Run tests
159+
run: cargo test --verbose
160+
- name: Run with only 'alloc' enabled
161+
run: cargo test --verbose --no-default-features --features alloc
162+
- name: Run tests without any features enabled (core-only)
163+
run: cargo test --verbose --no-default-features
164+
165+
# Setup and run tests on the wasm32-wasi target via wasmtime, but without
166+
# simd128 enabled.
167+
wasm-no-simd128:
168+
runs-on: ubuntu-latest
169+
env:
170+
# The version of wasmtime to download and install.
171+
WASMTIME_VERSION: 15.0.1
172+
steps:
173+
- name: Checkout repository
174+
uses: actions/checkout@v4
175+
- name: Install Rust
176+
uses: dtolnay/rust-toolchain@master
177+
with:
178+
toolchain: stable
179+
- name: Add wasm32-wasi target
180+
run: rustup target add wasm32-wasi
181+
- name: Download and install Wasmtime
182+
run: |
183+
echo "CARGO_BUILD_TARGET=wasm32-wasi" >> $GITHUB_ENV
184+
echo "RUSTFLAGS=-Ctarget-feature=-simd128" >> $GITHUB_ENV
185+
curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v$WASMTIME_VERSION/wasmtime-v$WASMTIME_VERSION-x86_64-linux.tar.xz
186+
tar xvf wasmtime-v$WASMTIME_VERSION-x86_64-linux.tar.xz
187+
echo `pwd`/wasmtime-v$WASMTIME_VERSION-x86_64-linux >> $GITHUB_PATH
188+
echo "CARGO_TARGET_WASM32_WASI_RUNNER=wasmtime run --" >> $GITHUB_ENV
156189
- name: Basic build
157190
run: cargo build --verbose
158191
- name: Run tests

src/arch/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub(crate) mod generic;
1010

1111
#[cfg(target_arch = "aarch64")]
1212
pub mod aarch64;
13-
#[cfg(target_arch = "wasm32")]
13+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
1414
pub mod wasm32;
1515
#[cfg(target_arch = "x86_64")]
1616
pub mod x86_64;

src/arch/wasm32/memchr.rs

+7-20
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,14 @@ available for `wasm32` targets.)
88

99
macro_rules! defraw {
1010
($ty:ident, $find:ident, $start:ident, $end:ident, $($needles:ident),+) => {{
11-
#[cfg(target_feature = "simd128")]
12-
{
13-
use crate::arch::wasm32::simd128::memchr::$ty;
11+
use crate::arch::wasm32::simd128::memchr::$ty;
1412

15-
debug!("chose simd128 for {}", stringify!($ty));
16-
debug_assert!($ty::is_available());
17-
// SAFETY: We know that wasm memchr is always available whenever
18-
// code is compiled for `wasm32` with the `simd128` target feature
19-
// enabled.
20-
$ty::new_unchecked($($needles),+).$find($start, $end)
21-
}
22-
#[cfg(not(target_feature = "simd128"))]
23-
{
24-
use crate::arch::all::memchr::$ty;
25-
26-
debug!(
27-
"no simd128 feature available, using fallback for {}",
28-
stringify!($ty),
29-
);
30-
$ty::new($($needles),+).$find($start, $end)
31-
}
13+
debug!("chose simd128 for {}", stringify!($ty));
14+
debug_assert!($ty::is_available());
15+
// SAFETY: We know that wasm memchr is always available whenever
16+
// code is compiled for `wasm32` with the `simd128` target feature
17+
// enabled.
18+
$ty::new_unchecked($($needles),+).$find($start, $end)
3219
}}
3320
}
3421

src/arch/wasm32/simd128/packedpair.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,13 @@ impl Finder {
8181
/// true then it will always return true.
8282
#[inline]
8383
pub fn is_available() -> bool {
84-
#[cfg(target_feature = "simd128")]
85-
{
86-
true
87-
}
88-
#[cfg(not(target_feature = "simd128"))]
89-
{
90-
false
91-
}
84+
// We used to gate on `cfg(target_feature = "simd128")` here, but
85+
// we've since required the feature to be enabled at compile time to
86+
// even include this module at all. Therefore, it is always enabled
87+
// in this context. See the linked issue for why this was changed.
88+
//
89+
// Ref: https://github.com/BurntSushi/memchr/issues/144
90+
true
9291
}
9392

9493
/// Execute a search using wasm32 v128 vectors and routines.

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ Originally, this crate was literally just a safe wrapper function around the
177177
#![cfg_attr(
178178
not(any(
179179
all(target_arch = "x86_64", target_feature = "sse2"),
180-
target_arch = "wasm32",
180+
all(target_arch = "wasm32", target_feature = "simd128"),
181181
target_arch = "aarch64",
182182
)),
183183
allow(dead_code)

src/memchr.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ unsafe fn memchr_raw(
514514
// nor SSE2 (unusual) are available.
515515
crate::arch::x86_64::memchr::memchr_raw(needle, start, end)
516516
}
517-
#[cfg(target_arch = "wasm32")]
517+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
518518
{
519519
crate::arch::wasm32::memchr::memchr_raw(needle, start, end)
520520
}
@@ -524,7 +524,7 @@ unsafe fn memchr_raw(
524524
}
525525
#[cfg(not(any(
526526
target_arch = "x86_64",
527-
target_arch = "wasm32",
527+
all(target_arch = "wasm32", target_feature = "simd128"),
528528
target_arch = "aarch64"
529529
)))]
530530
{
@@ -547,7 +547,7 @@ unsafe fn memrchr_raw(
547547
{
548548
crate::arch::x86_64::memchr::memrchr_raw(needle, start, end)
549549
}
550-
#[cfg(target_arch = "wasm32")]
550+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
551551
{
552552
crate::arch::wasm32::memchr::memrchr_raw(needle, start, end)
553553
}
@@ -557,7 +557,7 @@ unsafe fn memrchr_raw(
557557
}
558558
#[cfg(not(any(
559559
target_arch = "x86_64",
560-
target_arch = "wasm32",
560+
all(target_arch = "wasm32", target_feature = "simd128"),
561561
target_arch = "aarch64"
562562
)))]
563563
{
@@ -581,7 +581,7 @@ unsafe fn memchr2_raw(
581581
{
582582
crate::arch::x86_64::memchr::memchr2_raw(needle1, needle2, start, end)
583583
}
584-
#[cfg(target_arch = "wasm32")]
584+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
585585
{
586586
crate::arch::wasm32::memchr::memchr2_raw(needle1, needle2, start, end)
587587
}
@@ -591,7 +591,7 @@ unsafe fn memchr2_raw(
591591
}
592592
#[cfg(not(any(
593593
target_arch = "x86_64",
594-
target_arch = "wasm32",
594+
all(target_arch = "wasm32", target_feature = "simd128"),
595595
target_arch = "aarch64"
596596
)))]
597597
{
@@ -616,7 +616,7 @@ unsafe fn memrchr2_raw(
616616
{
617617
crate::arch::x86_64::memchr::memrchr2_raw(needle1, needle2, start, end)
618618
}
619-
#[cfg(target_arch = "wasm32")]
619+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
620620
{
621621
crate::arch::wasm32::memchr::memrchr2_raw(needle1, needle2, start, end)
622622
}
@@ -628,7 +628,7 @@ unsafe fn memrchr2_raw(
628628
}
629629
#[cfg(not(any(
630630
target_arch = "x86_64",
631-
target_arch = "wasm32",
631+
all(target_arch = "wasm32", target_feature = "simd128"),
632632
target_arch = "aarch64"
633633
)))]
634634
{
@@ -656,7 +656,7 @@ unsafe fn memchr3_raw(
656656
needle1, needle2, needle3, start, end,
657657
)
658658
}
659-
#[cfg(target_arch = "wasm32")]
659+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
660660
{
661661
crate::arch::wasm32::memchr::memchr3_raw(
662662
needle1, needle2, needle3, start, end,
@@ -670,7 +670,7 @@ unsafe fn memchr3_raw(
670670
}
671671
#[cfg(not(any(
672672
target_arch = "x86_64",
673-
target_arch = "wasm32",
673+
all(target_arch = "wasm32", target_feature = "simd128"),
674674
target_arch = "aarch64"
675675
)))]
676676
{
@@ -698,7 +698,7 @@ unsafe fn memrchr3_raw(
698698
needle1, needle2, needle3, start, end,
699699
)
700700
}
701-
#[cfg(target_arch = "wasm32")]
701+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
702702
{
703703
crate::arch::wasm32::memchr::memrchr3_raw(
704704
needle1, needle2, needle3, start, end,
@@ -712,7 +712,7 @@ unsafe fn memrchr3_raw(
712712
}
713713
#[cfg(not(any(
714714
target_arch = "x86_64",
715-
target_arch = "wasm32",
715+
all(target_arch = "wasm32", target_feature = "simd128"),
716716
target_arch = "aarch64"
717717
)))]
718718
{
@@ -732,7 +732,7 @@ unsafe fn count_raw(needle: u8, start: *const u8, end: *const u8) -> usize {
732732
{
733733
crate::arch::x86_64::memchr::count_raw(needle, start, end)
734734
}
735-
#[cfg(target_arch = "wasm32")]
735+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
736736
{
737737
crate::arch::wasm32::memchr::count_raw(needle, start, end)
738738
}
@@ -742,7 +742,7 @@ unsafe fn count_raw(needle: u8, start: *const u8, end: *const u8) -> usize {
742742
}
743743
#[cfg(not(any(
744744
target_arch = "x86_64",
745-
target_arch = "wasm32",
745+
all(target_arch = "wasm32", target_feature = "simd128"),
746746
target_arch = "aarch64"
747747
)))]
748748
{

src/memmem/searcher.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::arch::all::{
55

66
#[cfg(target_arch = "aarch64")]
77
use crate::arch::aarch64::neon::packedpair as neon;
8-
#[cfg(target_arch = "wasm32")]
8+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
99
use crate::arch::wasm32::simd128::packedpair as simd128;
1010
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
1111
use crate::arch::x86_64::{
@@ -109,7 +109,7 @@ impl Searcher {
109109
Searcher::twoway(needle, rabinkarp, prestrat)
110110
}
111111
}
112-
#[cfg(target_arch = "wasm32")]
112+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
113113
{
114114
if let Some(pp) = simd128::Finder::with_pair(needle, pair) {
115115
if do_packed_search(needle) {
@@ -151,7 +151,7 @@ impl Searcher {
151151
}
152152
#[cfg(not(any(
153153
all(target_arch = "x86_64", target_feature = "sse2"),
154-
target_arch = "wasm32",
154+
all(target_arch = "wasm32", target_feature = "simd128"),
155155
target_arch = "aarch64"
156156
)))]
157157
{
@@ -251,7 +251,7 @@ union SearcherKind {
251251
sse2: crate::arch::x86_64::sse2::packedpair::Finder,
252252
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
253253
avx2: crate::arch::x86_64::avx2::packedpair::Finder,
254-
#[cfg(target_arch = "wasm32")]
254+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
255255
simd128: crate::arch::wasm32::simd128::packedpair::Finder,
256256
#[cfg(target_arch = "aarch64")]
257257
neon: crate::arch::aarch64::neon::packedpair::Finder,
@@ -400,7 +400,7 @@ unsafe fn searcher_kind_avx2(
400400
/// # Safety
401401
///
402402
/// Callers must ensure that the `searcher.kind.simd128` union field is set.
403-
#[cfg(target_arch = "wasm32")]
403+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
404404
unsafe fn searcher_kind_simd128(
405405
searcher: &Searcher,
406406
_prestate: &mut PrefilterState,
@@ -671,7 +671,7 @@ impl Prefilter {
671671
}
672672

673673
/// Return a prefilter using a wasm32 simd128 vector algorithm.
674-
#[cfg(target_arch = "wasm32")]
674+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
675675
#[inline]
676676
fn simd128(finder: simd128::Finder, needle: &[u8]) -> Prefilter {
677677
trace!("building wasm32 simd128 prefilter");
@@ -761,7 +761,7 @@ union PrefilterKind {
761761
sse2: crate::arch::x86_64::sse2::packedpair::Finder,
762762
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
763763
avx2: crate::arch::x86_64::avx2::packedpair::Finder,
764-
#[cfg(target_arch = "wasm32")]
764+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
765765
simd128: crate::arch::wasm32::simd128::packedpair::Finder,
766766
#[cfg(target_arch = "aarch64")]
767767
neon: crate::arch::aarch64::neon::packedpair::Finder,
@@ -833,7 +833,7 @@ unsafe fn prefilter_kind_avx2(
833833
/// # Safety
834834
///
835835
/// Callers must ensure that the `strat.kind.simd128` union field is set.
836-
#[cfg(target_arch = "wasm32")]
836+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
837837
unsafe fn prefilter_kind_simd128(
838838
strat: &Prefilter,
839839
haystack: &[u8],

src/vector.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ mod aarch64neon {
464464
}
465465
}
466466

467-
#[cfg(target_arch = "wasm32")]
467+
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
468468
mod wasm_simd128 {
469469
use core::arch::wasm32::*;
470470

0 commit comments

Comments
 (0)