Skip to content

Commit b7a1daf

Browse files
alexcrichtonAmanieu
authored andcommitted
Document safety conditions of simd shifts
1 parent d4a26b9 commit b7a1daf

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

crates/core_arch/src/wasm32/simd128.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2318,6 +2318,24 @@ pub fn u8x16_narrow_i16x8(a: v128, b: v128) -> v128 {
23182318
#[doc(alias("i8x16.shl"))]
23192319
#[stable(feature = "wasm_simd", since = "1.54.0")]
23202320
pub fn i8x16_shl(a: v128, amt: u32) -> v128 {
2321+
// SAFETY: the safety of this intrinsic relies on the fact that the
2322+
// shift amount for each lane is less than the number of bits in the input
2323+
// lane. In this case the input has 8-bit lanes but the shift amount above
2324+
// is `u32`, so a mask is required to discard all the upper bits of `amt` to
2325+
// ensure that the safety condition is met.
2326+
//
2327+
// Note that this is distinct from the behavior of the native WebAssembly
2328+
// instruction here where WebAssembly defines this instruction as performing
2329+
// a mask as well. This is nonetheless required since this must have defined
2330+
// semantics in LLVM, not just WebAssembly.
2331+
//
2332+
// Finally note that this mask operation is not actually emitted into the
2333+
// final binary itself. LLVM understands that the wasm operation implicitly
2334+
// masks, so it knows this mask operation is redundant.
2335+
//
2336+
// Basically the extra mask here is required as a bridge from the documented
2337+
// semantics through LLVM back out to WebAssembly. Both ends have the
2338+
// documented semantics, and the mask is required by LLVM in the middle.
23212339
unsafe { simd_shl(a.as_i8x16(), simd::i8x16::splat((amt & 0x7) as i8)).v128() }
23222340
}
23232341

@@ -2335,6 +2353,8 @@ pub use i8x16_shl as u8x16_shl;
23352353
#[doc(alias("i8x16.shr_s"))]
23362354
#[stable(feature = "wasm_simd", since = "1.54.0")]
23372355
pub fn i8x16_shr(a: v128, amt: u32) -> v128 {
2356+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
2357+
// essentially the shift amount must be valid hence the mask.
23382358
unsafe { simd_shr(a.as_i8x16(), simd::i8x16::splat((amt & 0x7) as i8)).v128() }
23392359
}
23402360

@@ -2349,6 +2369,8 @@ pub fn i8x16_shr(a: v128, amt: u32) -> v128 {
23492369
#[doc(alias("i8x16.shr_u"))]
23502370
#[stable(feature = "wasm_simd", since = "1.54.0")]
23512371
pub fn u8x16_shr(a: v128, amt: u32) -> v128 {
2372+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
2373+
// essentially the shift amount must be valid hence the mask.
23522374
unsafe { simd_shr(a.as_u8x16(), simd::u8x16::splat((amt & 0x7) as u8)).v128() }
23532375
}
23542376

@@ -2686,6 +2708,8 @@ pub use i16x8_extend_high_u8x16 as u16x8_extend_high_u8x16;
26862708
#[doc(alias("i16x8.shl"))]
26872709
#[stable(feature = "wasm_simd", since = "1.54.0")]
26882710
pub fn i16x8_shl(a: v128, amt: u32) -> v128 {
2711+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
2712+
// essentially the shift amount must be valid hence the mask.
26892713
unsafe { simd_shl(a.as_i16x8(), simd::i16x8::splat((amt & 0xf) as i16)).v128() }
26902714
}
26912715

@@ -2703,6 +2727,8 @@ pub use i16x8_shl as u16x8_shl;
27032727
#[doc(alias("i16x8.shr_s"))]
27042728
#[stable(feature = "wasm_simd", since = "1.54.0")]
27052729
pub fn i16x8_shr(a: v128, amt: u32) -> v128 {
2730+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
2731+
// essentially the shift amount must be valid hence the mask.
27062732
unsafe { simd_shr(a.as_i16x8(), simd::i16x8::splat((amt & 0xf) as i16)).v128() }
27072733
}
27082734

@@ -2717,6 +2743,8 @@ pub fn i16x8_shr(a: v128, amt: u32) -> v128 {
27172743
#[doc(alias("i16x8.shr_u"))]
27182744
#[stable(feature = "wasm_simd", since = "1.54.0")]
27192745
pub fn u16x8_shr(a: v128, amt: u32) -> v128 {
2746+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
2747+
// essentially the shift amount must be valid hence the mask.
27202748
unsafe { simd_shr(a.as_u16x8(), simd::u16x8::splat((amt & 0xf) as u16)).v128() }
27212749
}
27222750

@@ -3136,6 +3164,8 @@ pub use i32x4_extend_high_u16x8 as u32x4_extend_high_u16x8;
31363164
#[doc(alias("i32x4.shl"))]
31373165
#[stable(feature = "wasm_simd", since = "1.54.0")]
31383166
pub fn i32x4_shl(a: v128, amt: u32) -> v128 {
3167+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
3168+
// essentially the shift amount must be valid hence the mask.
31393169
unsafe { simd_shl(a.as_i32x4(), simd::i32x4::splat((amt & 0x1f) as i32)).v128() }
31403170
}
31413171

@@ -3153,6 +3183,8 @@ pub use i32x4_shl as u32x4_shl;
31533183
#[doc(alias("i32x4.shr_s"))]
31543184
#[stable(feature = "wasm_simd", since = "1.54.0")]
31553185
pub fn i32x4_shr(a: v128, amt: u32) -> v128 {
3186+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
3187+
// essentially the shift amount must be valid hence the mask.
31563188
unsafe { simd_shr(a.as_i32x4(), simd::i32x4::splat((amt & 0x1f) as i32)).v128() }
31573189
}
31583190

@@ -3167,6 +3199,8 @@ pub fn i32x4_shr(a: v128, amt: u32) -> v128 {
31673199
#[doc(alias("i32x4.shr_u"))]
31683200
#[stable(feature = "wasm_simd", since = "1.54.0")]
31693201
pub fn u32x4_shr(a: v128, amt: u32) -> v128 {
3202+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
3203+
// essentially the shift amount must be valid hence the mask.
31703204
unsafe { simd_shr(a.as_u32x4(), simd::u32x4::splat(amt & 0x1f)).v128() }
31713205
}
31723206

@@ -3502,6 +3536,8 @@ pub use i64x2_extend_high_u32x4 as u64x2_extend_high_u32x4;
35023536
#[doc(alias("i64x2.shl"))]
35033537
#[stable(feature = "wasm_simd", since = "1.54.0")]
35043538
pub fn i64x2_shl(a: v128, amt: u32) -> v128 {
3539+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
3540+
// essentially the shift amount must be valid hence the mask.
35053541
unsafe { simd_shl(a.as_i64x2(), simd::i64x2::splat((amt & 0x3f) as i64)).v128() }
35063542
}
35073543

@@ -3519,6 +3555,8 @@ pub use i64x2_shl as u64x2_shl;
35193555
#[doc(alias("i64x2.shr_s"))]
35203556
#[stable(feature = "wasm_simd", since = "1.54.0")]
35213557
pub fn i64x2_shr(a: v128, amt: u32) -> v128 {
3558+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
3559+
// essentially the shift amount must be valid hence the mask.
35223560
unsafe { simd_shr(a.as_i64x2(), simd::i64x2::splat((amt & 0x3f) as i64)).v128() }
35233561
}
35243562

@@ -3533,6 +3571,8 @@ pub fn i64x2_shr(a: v128, amt: u32) -> v128 {
35333571
#[doc(alias("i64x2.shr_u"))]
35343572
#[stable(feature = "wasm_simd", since = "1.54.0")]
35353573
pub fn u64x2_shr(a: v128, amt: u32) -> v128 {
3574+
// SAFETY: see i8x16_shl for more documentation why this is unsafe,
3575+
// essentially the shift amount must be valid hence the mask.
35363576
unsafe { simd_shr(a.as_u64x2(), simd::u64x2::splat((amt & 0x3f) as u64)).v128() }
35373577
}
35383578

0 commit comments

Comments
 (0)