Repository navigation
SIMD tracking issue. #64170
Copy link
Copy link
Open
Labels
area-sdkUse area-sdk for general purpose SDK issues (packaging, distribution, …).Use area-sdk for general purpose SDK issues (packaging, distribution, …).library-typed-data
Description
The following (incomplete, work in progress) tables track our SIMD value types and my progress on them so far. Many things below are aspirational and will need a separate discussion.
If you have a use case you would like to implement with SIMD, or if you run into problems, please open an issue and mention @modulovalue and I will take a look.
Int32x4
| Operation | API | Codegen optimizations | Benchmark | Issues |
|---|---|---|---|---|
splat |
✅ cl/531960 | ✅ cl/531960, cl/550200 | ❓ | |
zero (+ identity) |
✅ cl/544840 | 🚧 | ❓ | |
one (* identity) |
🚧 | 🚧 | ❓ | |
const constructor |
🚧 | 🚧 | ❓ | #31487 |
+ (add) |
✅ | ✅ cl/497000 | ✅ SimdInt32x4 |
|
- (subtract) |
✅ | ✅ cl/497000 | ✅ SimdInt32x4 |
|
* (multiply) |
🚧 cl/551260 | 🚧 | ❓ | #59816 |
unary - (sign negation) |
✅ cl/545361 | 🚧 | ❓ | |
& (and) |
✅ | ✅ cl/497000 | ✅ SimdInt32x4, BitArray32x4 |
|
| (or) |
✅ | ✅ cl/497000 | ✅ SimdInt32x4, BitArray32x4 |
|
^ (xor) |
✅ | ✅ cl/497000 | ✅ SimdInt32x4, BitArray32x4 |
|
~ (not) |
✅ cl/532480 | ✅ cl/532480 | TODO extend BitArray32x4 |
|
andNot |
✅ cl/551000 | ✅ cl/558762 | TODO extend BitArray32x4 |
|
<< (shiftLeft) |
✅ cl/545480 | ✅ dart2wasm cl/547880, VM cl/553360 | ❓ | #47114, #63680 |
>> (shiftRight) |
✅ cl/545480 | ✅ dart2wasm cl/547880, VM cl/553360 | ❓ | #47114, #63680 |
>>> (shiftRightUnsigned) |
✅ cl/557620 | ✅ dart2wasm cl/557620, VM cl/560562 | ❓ | #64345 |
equal |
✅ cl/528620 | ✅ cl/539060, cl/539520 | ✅ SimdSearch |
|
notEqual |
✅ cl/541221 | ✅ cl/541240 | TODO extend SimdSearch |
|
< (lessThan) |
✅ cl/543500 | 🚧 dart2wasm ✅ cl/547880, VM in progress | ❓ | #63680 |
<= (lessThanOrEqual) |
✅ cl/543500 | 🚧 dart2wasm ✅ cl/547880, VM in progress | ❓ | #63680 |
> (greaterThan) |
✅ cl/543500 | 🚧 dart2wasm ✅ cl/547880, VM in progress | ❓ | #63680 |
>= (greaterThanOrEqual) |
✅ cl/543500 | 🚧 dart2wasm ✅ cl/547880, VM in progress | ❓ | #63680 |
min |
✅ cl/551040 | 🚧 dart2wasm ✅ cl/547880, VM in progress | ❓ | |
max |
✅ cl/551040 | 🚧 dart2wasm ✅ cl/547880, VM in progress | ❓ | |
abs |
✅ cl/545361 | 🚧 dart2wasm ✅ cl/547880, VM pending | ❓ | |
anyTrue |
✅ cl/528620 | ✅ cl/539400 | ✅ SimdSearch |
#64129 |
allTrue |
✅ cl/543480 | ✅ cl/551641 | ❓ | #64129 |
signMask |
✅ | ✅ cl/521245, cl/542362, cl/542363 | ✅ SimdInt32x4 |
#63680 |
x/y/z/w |
✅ | ✅ cl/507761 | ✅ BitArray32x4 |
|
flagX/Y/Z/W |
✅ | ✅ | ❓ | #64129 |
withX/Y/Z/W |
✅ | ✅ cl/550201 | ❓ | |
withFlagX/Y/Z/W |
✅ | ✅ | ❓ | #64129 |
shuffle |
✅ | ✅ cl/559002, arm64 cl/562680, cl/562681, cl/563880, cl/563881 | ❓ | #63680 |
shuffleMix |
✅ | ✅ cl/559002, arm64 cl/562680, cl/562681, cl/563880, cl/563881 | ❓ | |
swizzle |
🚧 | 🚧 | ❓ | |
select |
✅ | ✅ | ❓ | |
== / hashCode |
🚧 in progress | 🚧 in progress | ❓ | #43255 |
toString |
✅ cl/547261 | ✅ cl/547261 | ❓ | #63847 |
conversions (fromFloat32x4Bits) |
🚧 | ❓ | ❓ | #46182 |
Float32x4
Float64x2
| Operation | API | Codegen optimizations | Benchmark | Issues |
|---|---|---|---|---|
splat |
✅ | ✅ | ❓ | |
zero (+ identity) |
✅ | ✅ | ❓ | |
one (* identity) |
🚧 | 🚧 | ❓ | |
const constructor |
🚧 | 🚧 | ❓ | #31487 |
+ (add) |
✅ | ✅ | ❓ | |
- (subtract) |
✅ | ✅ | ❓ | |
* (multiply) |
✅ | ✅ | ❓ | |
/ (divide) |
✅ | ✅ | ❓ | |
unary - (sign negation) |
✅ | ✅ | ❓ | |
abs |
✅ | ✅ | ❓ | |
min |
✅ | ✅ cl/543520, cl/562661 | ❓ | #63962, #31048, #64521 |
max |
✅ | ✅ cl/543520, cl/562661 | ❓ | #63962, #31048, #64521 |
sqrt |
✅ | ✅ | ❓ | |
scale |
✅ | ✅ | ❓ | |
clamp |
✅ | ✅ cl/549060 | ❓ | #40426 |
ceil |
🚧 | 🚧 | ❓ | |
floor |
🚧 | 🚧 | ❓ | |
trunc |
🚧 | 🚧 | ❓ | |
nearest |
🚧 | 🚧 | ❓ | #61240 |
pmin |
🚧 | 🚧 | ❓ | |
pmax |
🚧 | 🚧 | ❓ | |
equal |
🚧 | 🚧 | ❓ | |
notEqual |
🚧 | 🚧 | ❓ | |
< (lessThan) |
🚧 | 🚧 | ❓ | |
<= (lessThanOrEqual) |
🚧 | 🚧 | ❓ | |
> (greaterThan) |
🚧 | 🚧 | ❓ | |
>= (greaterThanOrEqual) |
🚧 | 🚧 | ❓ | |
signMask |
✅ | ✅ cl/542363 | ❓ | |
x/y |
✅ | ✅ | ❓ | |
withX/Y |
✅ | ✅ | ❓ | |
== / hashCode |
🚧 in progress | 🚧 in progress | ❓ | #43255 |
toString |
✅ cl/547261 | ✅ cl/547261 | ❓ | #63847 |
conversions (fromFloat32x4) |
🚧 | ❓ | ❓ | #46182 |
Int8x16 / Uint8x16, Int16x8 / Uint16x8, Uint32x4, Int64x2
They are on my todo list. We don't have types for those yet (#63471).
The wasm level groundwork has landed: WasmI8x16 cl/551701, WasmI16x8 cl/551702, WasmI64x2 cl/551700.
🚧 In progress: a Uint8x16 value type on the VM (unboxing, arithmetic, equal, anyTrue), not uploaded yet.
Priorities
Because there's a lot to do, I decided to focus on what's most important, and deprioritize certain parts:
pmin/pmax&relaxed_min/relaxed_max:pmin/pmaxbenefits x86 and hurts arm64.relaxed_min/relaxed_maxrestores performance on arm64 tomin/maxlevels. Since float64 and float32 use cases are most relevant for Flutter, where most of our users are on arm64, min and max is already optimal for most of our users.- x86 would benefit from commutativity exposed in TFA for better code generation.
- operations that are not part of the Wasm SIMD API surface (e.g., rotateRight/rotateLeft) will be investigated later.
Third-party blockers
- Efficient
WasmArrayreinterpretation: [dart2wasm, typed_data] Support efficient WasmArray reinterpretation. #64256
Use cases
- Optimal 4x4 matrix multiplication: [SIMD] Support optimal 4x4 matrix multiplication. #64238
- Vectorized search over bytes: [simd] Support vectorized search over bytes. #63821
- Memory comparisons: [dart:typed_data] Add native memory range comparison API (memcmp / memoryEqualsRange) for TypedData #64095
- Efficient general purpose non-cryptographic hashing: Support an efficient general purpose hashing function via XXH3-64. #64359 & Speed up analyzer source reading and hashing with Rust and XXH3-128 #64065
- Efficient general purpose cryptographic hashing via BLAKE3: cl/553040, Add Int32x4.rotateRight #64345,
>>>landed (cl/557620, cl/560562), 🚧 lane rotation lowering in progress - 8-bit image codecs (libwebp VP8 encoder: DCT, Hadamard, SSD, quantizer): SIMD tracking issue. #64170 (comment), needs
Int32x4*(Support multiplication on Int32x4 #59816) and 8-bit lanes ([SIMD] Support for Int8x16 and Int8x16List. #63471)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area-sdkUse area-sdk for general purpose SDK issues (packaging, distribution, …).Use area-sdk for general purpose SDK issues (packaging, distribution, …).library-typed-data
Activity
[typed_data] Add Int32x4.notEqual
[vm] Add vsshr_4s to the arm64 assembler
[vm] Intrinsify Int32x4.notEqual
[benchmarks] Add SimdFields, covering SIMD values in instance fields
krll-kov commentedon Sep 4, 2026
@modulovalue
A use case, since the issue asks for them. I'm porting libwebp's VP8 encoder to Dart. The inner kernels are a typical 8-bit image workload: forward and inverse 4x4 DCT, a Hadamard distortion metric, sums of squared differences, and a quantizer. All of them read
Uint8Listat a fixed row stride, and libwebp has NEON and SSE versions of all of them.Here is what I ran into trying to vectorize them with
dart compile exeon macos_arm64.Arithmetic over a populated
Float32x4Listis fine, 2.5x faster than the same scalar loop. The problem is getting byte data into the lanes. Each lane has to be filled separately, and the int to double conversion is about 5x slower in AOT than in JIT. That alone made a vectorized 16x16 SSD 3x slower than the scalar version. I filed that as #64209. Writing the conversion as0.0 + xinstead ofx.toDouble()avoids it, and then the same kernel is 14% faster than scalar.With that out of the way, what still blocks the rest:
Int32x4has no*(Support multiplication on Int32x4 #59816), so an integer kernel can't stay in integer lanes. The DCT multiplies by 2217, 5352, 20091 and 35468, and the quantizer multiplies by a reciprocal, so both need it.Float32x4can't cover for that. It's only exact up to 2^24, and the second pass of the DCT reaches about 8.7e7 while the quantizer'scoeff * iqreaches about 1e9. Only the Hadamard metric and the SSD stay in the exact range.So right now SIMD pays off in one kernel out of five and loses in the others.
[vm] Finish Int32x4 unboxing, symmetric to the float SIMD value types
[vm] Use an SSHR-based sign mask on arm64
[vm] Bound the Simd sign mask result range
[typed_data] Add Int32x4.allTrue
[typed_data] Add Int32x4 signed ordered comparisons
34 remaining items
[vm] x64: add pshufd
[typed_data] Implement IEEE min/max for Float32x4/Float64x2 and add a…
[vm] arm64: add tbl
[vm, dart2wasm] lower 32x4 shuffles with pshufd, tbl and i8x16.swizzle
[vm] x64: add psrld
[vm] arm64: add ushl in its 4S form
[vm] Intrinsify Int32x4 operator >>>
[vm] Implement Float32x4 and Float64x2 SIMD fallbacks in Dart
[typed_data] Implement Float32x4 and Float64x2 clamp with min and max
[vm, compiler] Fold Float32x4/Float64x2 min and max with Dart semantics
[vm] arm64: give 32x4 shuffles their own emitters
[vm] arm64: use rev64 for 32x4 shuffles
[vm] arm64: use ext for 32x4 shuffles
[vm] Remove the Float32 and Float64 native fallbacks of typed lists
[vm] arm64: use ins for one-lane 32x4 shuffles