Commit 4e28c96
[wasm] Enable Vector128 fast paths on Wasm via PackedSimd: hex/Guid, UTF-8, SearchValues, Teddy, Adler32/XXH3 (#129838)
Enable several `Vector128` fast paths in CoreLib and `System.IO.Hashing`
on browser-wasm by adding a `PackedSimd.IsSupported` branch alongside
the existing `Sse2`/`Ssse3`/`AdvSimd.Arm64` gates. Before these changes,
the SIMD code paths were unreachable on Wasm even though the wasm
runtime supports PackedSimd (the test pipeline default sets
`WasmEnableSIMD=true`).
## Scope and commits
| # | Commit | Area |
|---|--------|------|
| 1 | `c69998277eb` `0e99f4a194c` | Add Wasm `PackedSimd` path to
`Vector128.UnpackLow/UnpackHigh` (composed from two `PackedSimd.Swizzle`
calls + OR; the two-vector `PackedSimd.Shuffle` requires constant lane
indices and is impractical from generic code). |
| 2 | `3dc956b6465` | Enable Vector128 hex/Guid format fast path on Wasm
— widen the gates on `HexConverter.AsciiToHexVector128`,
`HexConverter.EncodeToUtf8/Utf16`, `HexConverter.EncodeTo_Vector128`,
and `Guid.FormatGuidVector128Utf8`. Bodies were already portable
(`Vector128.ShuffleNative`, `Vector128.UnpackLow/High`, constant-index
`Vector128.Shuffle`). |
| 3 | `061b22bffcf` `2543702633` | Vectorize `Utf8Utility.Validation`
ASCII fast path on Wasm — add a `PackedSimd` branch alongside
`AdvSimd.Arm64`/`Sse2` in the inner ASCII-scan loop of
`GetPointerToFirstInvalidChar`, using portable `Vector128.LoadUnsafe` +
`ExtractMostSignificantBits`. |
| 4 | `da08d905c6e` | Vectorize `Utf8Utility.Transcoding` ASCII fast
path on Wasm — the 8-char narrow-store loop and the two 4-char tail
stores, using `PackedSimd.ConvertNarrowingSaturateUnsigned`. |
| 5 | `2caa5e25997` `0e99f4a194c` | Enable Teddy multi-string search on
Wasm — `TeddyHelper.LoadAndPack16AsciiChars`, `GetNibbles`, two-table
`Shuffle`, `RightShift1/RightShift2` (composed from two
`PackedSimd.Swizzle` calls + OR), plus the
`StringSearchValues.CreateFromNormalizedValues` entry gate and
`AsciiStringSearchValuesTeddyBase.IndexOfAnyN2/N3`
`[CompExactlyDependsOn]`. |
| 6 | `819c9fe3960` | Enable `ProbabilisticMap` vectorized
`SearchValues<char>` on Wasm. Subtle because the bitmap **layout
itself** branches on the gate (`SetCharBit`/`IsCharBitSet`, marked
`[BypassReadyToRun]`). Widens the layout choice, `ContainsMask16Chars`
(new PackedSimd narrowing branch), the `IndexOfAny`/`LastIndexOfAny`
entry dispatcher, and the worker `[CompExactlyDependsOn]` attributes
consistently. |
| 7 | `80522ca629b` | `Adler32.UpdateVector128` and
`XxHashShared.MultiplyWideningLower`: replace the portable
`Vector128.Widen + multiply + add` sequences with
`PackedSimd.AddPairwiseWidening` + `MultiplyWideningLower/Upper` and
`PackedSimd.MultiplyWideningLower` (`i64x2.extmul_low_i32x4_u`). Already
vectorized on Wasm via the generic else branch; this turns 3–5 ops/iter
into 1. |
## Test results
Validated end-to-end with `WasmEnableSIMD=true` (the browser-wasm test
pipeline default).
| Suite | Host arm64 | browser-wasm (V8 v15) | Coverage |
|------|-----------|------------------------|----------|
| `System.Runtime.Tests` | 69,714 / 69,714 ✅ | 67,835 / 67,835 ✅ | Guid
format/parse |
| `System.Runtime.Extensions.Tests` | 8,350 / 8,350 ✅ | 8,224 / 8,224 ✅
| `Convert.ToHexString`/`FromHexString` |
| `System.Memory.Tests` | 52,906 / 52,906 ✅ | 52,249 / 52,249 ✅ | UTF-8
validation/transcoding, Ascii, `SearchValues<string>` (Teddy),
`SearchValues<char>` (ProbabilisticMap), `SpanHelpers` |
| `System.IO.Hashing.Tests` | 4,196 / 4,196 ✅ | 4,196 / 4,196 ✅ |
Adler32, XxHash (lane-order is checked end-to-end via the hash output
bytes — a swap would corrupt every hash) |
The original push exposed two AOT-only failure modes in browser-wasm
Helix legs:
1. `PackedSimd.Shuffle` (two-vector `i8x16.shuffle`) requires
compile-time-constant lane indices; Mono AOT can't fold a
`Vector128.Create(...)` operand and throws
`PlatformNotSupportedException`. Fixed in `c69998277eb` → `0e99f4a194c`
by composing with single-vector `PackedSimd.Swizzle` + OR.
2. The same pattern was originally applied in
`TeddyHelper.RightShift1/RightShift2` via `Vector128.ShuffleNative` (a
dispatcher with an `Ssse3 → AdvSimd.Arm64 → PackedSimd` if/else chain).
The Mono SIMD intrinsic recognizer doesn't always lower that chain
cleanly for less-traveled paths — the safer pattern is to call
`PackedSimd.Swizzle` directly under the `PackedSimd.IsSupported` branch.
Applied consistently in `0e99f4a194c`.
## Files changed
-
`src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs`
- `src/libraries/Common/src/System/HexConverter.cs`
- `src/libraries/System.Private.CoreLib/src/System/Guid.cs`
-
`src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Validation.cs`
-
`src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs`
-
`src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/TeddyHelper.cs`
-
`src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/StringSearchValues.cs`
-
`src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/AsciiStringSearchValuesTeddyBase.cs`
-
`src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs`
- `src/libraries/System.IO.Hashing/src/System/IO/Hashing/Adler32.cs`
-
`src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHashShared.cs`
## Not in this PR
- `Base64DecoderHelper` / `Base64EncoderHelper` — need `pmaddubsw` and
`pmulhuw` analogs composed from `MultiplyWideningLower/Upper` +
`AddPairwiseWidening` or `Dot`, with careful 8-short lane preservation.
Worth a dedicated follow-up with benchmarks.
> [!NOTE]
> This PR description and the commits in this branch were drafted with
AI/Copilot assistance.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 6fe369a commit 4e28c96
11 files changed
Lines changed: 173 additions & 30 deletions
File tree
- src/libraries
- Common/src/System
- System.IO.Hashing/src/System/IO/Hashing
- System.Private.CoreLib/src/System
- Runtime/Intrinsics
- SearchValues
- Strings
- Helpers
- Text/Unicode
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
| 99 | + | |
99 | 100 | | |
100 | 101 | | |
101 | | - | |
| 102 | + | |
102 | 103 | | |
103 | 104 | | |
104 | 105 | | |
| |||
115 | 116 | | |
116 | 117 | | |
117 | 118 | | |
| 119 | + | |
118 | 120 | | |
119 | 121 | | |
120 | 122 | | |
| |||
187 | 189 | | |
188 | 190 | | |
189 | 191 | | |
190 | | - | |
| 192 | + | |
191 | 193 | | |
192 | 194 | | |
193 | 195 | | |
| |||
204 | 206 | | |
205 | 207 | | |
206 | 208 | | |
207 | | - | |
| 209 | + | |
208 | 210 | | |
209 | 211 | | |
210 | 212 | | |
| |||
Lines changed: 18 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
300 | 301 | | |
301 | 302 | | |
302 | 303 | | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
303 | 321 | | |
304 | 322 | | |
305 | 323 | | |
| |||
Lines changed: 17 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
| |||
702 | 703 | | |
703 | 704 | | |
704 | 705 | | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
705 | 721 | | |
706 | 722 | | |
707 | 723 | | |
708 | | - | |
709 | | - | |
710 | | - | |
| 724 | + | |
711 | 725 | | |
712 | 726 | | |
713 | 727 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
1345 | 1346 | | |
1346 | 1347 | | |
1347 | 1348 | | |
1348 | | - | |
| 1349 | + | |
1349 | 1350 | | |
1350 | 1351 | | |
1351 | 1352 | | |
| |||
1513 | 1514 | | |
1514 | 1515 | | |
1515 | 1516 | | |
| 1517 | + | |
1516 | 1518 | | |
1517 | 1519 | | |
1518 | | - | |
| 1520 | + | |
1519 | 1521 | | |
1520 | 1522 | | |
1521 | 1523 | | |
| |||
Lines changed: 32 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4388 | 4388 | | |
4389 | 4389 | | |
4390 | 4390 | | |
| 4391 | + | |
4391 | 4392 | | |
4392 | 4393 | | |
4393 | 4394 | | |
4394 | 4395 | | |
4395 | 4396 | | |
4396 | 4397 | | |
4397 | | - | |
| 4398 | + | |
4398 | 4399 | | |
4399 | | - | |
| 4400 | + | |
| 4401 | + | |
| 4402 | + | |
| 4403 | + | |
| 4404 | + | |
| 4405 | + | |
| 4406 | + | |
| 4407 | + | |
| 4408 | + | |
| 4409 | + | |
| 4410 | + | |
| 4411 | + | |
| 4412 | + | |
| 4413 | + | |
| 4414 | + | |
4400 | 4415 | | |
4401 | | - | |
| 4416 | + | |
| 4417 | + | |
4402 | 4418 | | |
4403 | 4419 | | |
4404 | 4420 | | |
4405 | 4421 | | |
4406 | 4422 | | |
| 4423 | + | |
4407 | 4424 | | |
4408 | 4425 | | |
4409 | 4426 | | |
4410 | 4427 | | |
4411 | 4428 | | |
4412 | 4429 | | |
4413 | | - | |
| 4430 | + | |
4414 | 4431 | | |
4415 | | - | |
| 4432 | + | |
| 4433 | + | |
| 4434 | + | |
| 4435 | + | |
| 4436 | + | |
| 4437 | + | |
| 4438 | + | |
| 4439 | + | |
| 4440 | + | |
4416 | 4441 | | |
4417 | | - | |
| 4442 | + | |
| 4443 | + | |
4418 | 4444 | | |
4419 | 4445 | | |
4420 | 4446 | | |
Lines changed: 14 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
83 | | - | |
| 83 | + | |
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
| |||
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
95 | | - | |
| 95 | + | |
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
| |||
220 | 220 | | |
221 | 221 | | |
222 | 222 | | |
| 223 | + | |
223 | 224 | | |
224 | 225 | | |
225 | 226 | | |
| |||
238 | 239 | | |
239 | 240 | | |
240 | 241 | | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
241 | 247 | | |
242 | 248 | | |
243 | 249 | | |
| |||
392 | 398 | | |
393 | 399 | | |
394 | 400 | | |
395 | | - | |
| 401 | + | |
396 | 402 | | |
397 | 403 | | |
398 | 404 | | |
| |||
406 | 412 | | |
407 | 413 | | |
408 | 414 | | |
409 | | - | |
| 415 | + | |
410 | 416 | | |
411 | 417 | | |
412 | 418 | | |
| |||
501 | 507 | | |
502 | 508 | | |
503 | 509 | | |
| 510 | + | |
504 | 511 | | |
505 | 512 | | |
506 | 513 | | |
507 | | - | |
| 514 | + | |
508 | 515 | | |
509 | 516 | | |
510 | 517 | | |
| |||
679 | 686 | | |
680 | 687 | | |
681 | 688 | | |
| 689 | + | |
682 | 690 | | |
683 | 691 | | |
684 | 692 | | |
685 | | - | |
| 693 | + | |
686 | 694 | | |
687 | 695 | | |
688 | 696 | | |
| |||
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
150 | 151 | | |
151 | 152 | | |
152 | 153 | | |
| 154 | + | |
153 | 155 | | |
154 | 156 | | |
155 | 157 | | |
| |||
170 | 172 | | |
171 | 173 | | |
172 | 174 | | |
| 175 | + | |
173 | 176 | | |
174 | 177 | | |
175 | 178 | | |
| |||
190 | 193 | | |
191 | 194 | | |
192 | 195 | | |
| 196 | + | |
193 | 197 | | |
194 | 198 | | |
195 | 199 | | |
| |||
350 | 354 | | |
351 | 355 | | |
352 | 356 | | |
| 357 | + | |
353 | 358 | | |
354 | 359 | | |
355 | 360 | | |
| |||
0 commit comments