-
-
Notifications
You must be signed in to change notification settings - Fork 15.1k
Regression: Wasm32 SIMD128 narrow intrinsics stopped working correctly in Rust 1.95+ #157456
Copy link
Copy link
Open
Labels
A-SIMDArea: SIMD (Single Instruction Multiple Data)Area: SIMD (Single Instruction Multiple Data)C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchI-prioritizeIssue: Indicates that prioritization has been requested for this issue.Issue: Indicates that prioritization has been requested for this issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.Performance or correctness regression from one stable version to another.
Metadata
Metadata
Assignees
Labels
A-SIMDArea: SIMD (Single Instruction Multiple Data)Area: SIMD (Single Instruction Multiple Data)C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchI-prioritizeIssue: Indicates that prioritization has been requested for this issue.Issue: Indicates that prioritization has been requested for this issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.Performance or correctness regression from one stable version to another.
Type
Fields
Give feedbackNo fields configured for issues without a type.
I found that starting with Rust 1.95, all Wasm32 Simd128 narrowing intrinsics ("narrow" functions) stopped working correctly.
For example, u8x16_narrow_i16x8() takes a vector of i16 values and converts it to a vector of u8 values using saturating narrowing. In other words, negative values are clamped to 0, while values that are too large are clamped to 255.
However, there is no equivalent function that accepts a vector of u16 values. If the source vector contains u16s, the caller must manually clamp the upper bound first, for example with u16x8_min(x, 255). Otherwise, all values greater than i16::MAX will be interpreted as negative numbers and will be converted to 0 instead of 255.
This worked correctly before Rust 1.95. Starting with Rust 1.95, the compiler somehow decides that the u16x8_min(x, 255) operation is unnecessary in this case and safely removes it during optimization.
Other functions from the "narrow" group exhibit the same issue.
Here is a Godbolt example demonstrating the problem: https://rust.godbolt.org/z/1KeKzhe74
Code
I tried this code:
WASM code from Rust 1.94:
narrow_with_min local.get 0 local.get 1 v128.load 0:p2align=1 v128.const 255, 255, 255, 255, 255, 255, 255, 255 i16x8.min_u local.tee 2 local.get 2 i8x16.narrow_i16x8_u v128.store 0:p2align=0 end_functionWASM code from Rust 1.95:
narrow_with_min local.get 0 local.get 1 v128.load 0:p2align=1 local.tee 2 local.get 2 i8x16.narrow_i16x8_u v128.store 0:p2align=0 end_functionVersion it worked on
It most recently worked on: Rust 1.94.1
Version with regression
It is broken in Rust 1.95 and 1.96
But if I use a debug build without any optimizations, everything works correctly even in these versions of Rust. This is because the compiler doesn't remove
u16x8_min()from WASM.