From 62fdd57929936be8242e4ee2e21fb3b327e5bc15 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 5 Nov 2021 01:42:29 +0000 Subject: [PATCH 1/2] Add some safety comments --- crates/core_simd/src/lib.rs | 2 +- crates/core_simd/src/masks.rs | 3 +++ crates/core_simd/src/reduction.rs | 11 +++++++++++ crates/core_simd/src/swizzle.rs | 2 ++ crates/core_simd/src/vector.rs | 4 +++- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs index 960a6640083..68da82eadc1 100644 --- a/crates/core_simd/src/lib.rs +++ b/crates/core_simd/src/lib.rs @@ -11,7 +11,7 @@ #![cfg_attr(feature = "generic_const_exprs", feature(generic_const_exprs))] #![cfg_attr(feature = "generic_const_exprs", allow(incomplete_features))] #![warn(missing_docs)] -#![deny(unsafe_op_in_unsafe_fn)] +#![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)] #![unstable(feature = "portable_simd", issue = "86656")] //! Portable SIMD module. diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index d460da0d04f..e08e2439b3c 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -41,6 +41,9 @@ mod sealed { use sealed::Sealed; /// Marker trait for types that may be used as SIMD mask elements. +/// +/// # Safety +/// Type must be a signed integer. pub unsafe trait MaskElement: SimdElement + Sealed {} macro_rules! impl_element { diff --git a/crates/core_simd/src/reduction.rs b/crates/core_simd/src/reduction.rs index db0640aae79..170d4d09f54 100644 --- a/crates/core_simd/src/reduction.rs +++ b/crates/core_simd/src/reduction.rs @@ -13,12 +13,14 @@ macro_rules! impl_integer_reductions { /// Horizontal wrapping add. Returns the sum of the lanes of the vector, with wrapping addition. #[inline] pub fn horizontal_sum(self) -> $scalar { + // Safety: `self` is an integer vector unsafe { simd_reduce_add_ordered(self, 0) } } /// Horizontal wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication. #[inline] pub fn horizontal_product(self) -> $scalar { + // Safety: `self` is an integer vector unsafe { simd_reduce_mul_ordered(self, 1) } } @@ -26,6 +28,7 @@ macro_rules! impl_integer_reductions { /// the vector. #[inline] pub fn horizontal_and(self) -> $scalar { + // Safety: `self` is an integer vector unsafe { simd_reduce_and(self) } } @@ -33,6 +36,7 @@ macro_rules! impl_integer_reductions { /// the vector. #[inline] pub fn horizontal_or(self) -> $scalar { + // Safety: `self` is an integer vector unsafe { simd_reduce_or(self) } } @@ -40,18 +44,21 @@ macro_rules! impl_integer_reductions { /// the vector. #[inline] pub fn horizontal_xor(self) -> $scalar { + // Safety: `self` is an integer vector unsafe { simd_reduce_xor(self) } } /// Horizontal maximum. Returns the maximum lane in the vector. #[inline] pub fn horizontal_max(self) -> $scalar { + // Safety: `self` is an integer vector unsafe { simd_reduce_max(self) } } /// Horizontal minimum. Returns the minimum lane in the vector. #[inline] pub fn horizontal_min(self) -> $scalar { + // Safety: `self` is an integer vector unsafe { simd_reduce_min(self) } } } @@ -83,6 +90,7 @@ macro_rules! impl_float_reductions { if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { self.as_array().iter().sum() } else { + // Safety: `self` is a float vector unsafe { simd_reduce_add_ordered(self, 0.) } } } @@ -94,6 +102,7 @@ macro_rules! impl_float_reductions { if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { self.as_array().iter().product() } else { + // Safety: `self` is a float vector unsafe { simd_reduce_mul_ordered(self, 1.) } } } @@ -104,6 +113,7 @@ macro_rules! impl_float_reductions { /// return either. This function will not return `NaN` unless all lanes are `NaN`. #[inline] pub fn horizontal_max(self) -> $scalar { + // Safety: `self` is a float vector unsafe { simd_reduce_max(self) } } @@ -113,6 +123,7 @@ macro_rules! impl_float_reductions { /// return either. This function will not return `NaN` unless all lanes are `NaN`. #[inline] pub fn horizontal_min(self) -> $scalar { + // Safety: `self` is a float vector unsafe { simd_reduce_min(self) } } } diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index 88e7f3b223e..6a11115264c 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -93,6 +93,7 @@ pub trait Swizzle { LaneCount: SupportedLaneCount, LaneCount: SupportedLaneCount, { + // Safety: `vector` is a vector, and `INDEX_IMPL` is a const array of u32. unsafe { intrinsics::simd_shuffle(vector, vector, Self::INDEX_IMPL) } } } @@ -115,6 +116,7 @@ pub trait Swizzle2 { LaneCount: SupportedLaneCount, LaneCount: SupportedLaneCount, { + // Safety: `first` and `second` are vectors, and `INDEX_IMPL` is a const array of u32. unsafe { intrinsics::simd_shuffle(first, second, Self::INDEX_IMPL) } } } diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 893eff674ff..e353f4352dd 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -439,7 +439,9 @@ mod sealed { use sealed::Sealed; /// Marker trait for types that may be used as SIMD vector elements. -/// SAFETY: This trait, when implemented, asserts the compiler can monomorphize +/// +/// # Safety +/// This trait, when implemented, asserts the compiler can monomorphize /// `#[repr(simd)]` structs with the marked type as an element. /// Strictly, it is valid to impl if the vector will not be miscompiled. /// Practically, it is user-unfriendly to impl it if the vector won't compile, From b2a98a8f4d04bd7e8be43526e08ec2af373a0200 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 5 Nov 2021 02:19:11 +0000 Subject: [PATCH 2/2] Add more safety comments --- crates/core_simd/src/comparisons.rs | 12 ++++++++++++ crates/core_simd/src/masks.rs | 6 ++++++ crates/core_simd/src/masks/bitmask.rs | 18 ++++++++++++++---- crates/core_simd/src/masks/full_masks.rs | 8 ++++++++ crates/core_simd/src/math.rs | 4 ++++ crates/core_simd/src/ops.rs | 19 +++++++++++++++++++ crates/core_simd/src/round.rs | 6 ++++++ crates/core_simd/src/select.rs | 1 + crates/core_simd/src/to_bytes.rs | 2 ++ crates/core_simd/src/vector.rs | 8 ++++---- crates/core_simd/src/vector/float.rs | 5 +++++ crates/core_simd/src/vector/ptr.rs | 4 ++++ crates/core_simd/src/vendor.rs | 2 ++ 13 files changed, 87 insertions(+), 8 deletions(-) diff --git a/crates/core_simd/src/comparisons.rs b/crates/core_simd/src/comparisons.rs index 8c51baca8ed..88337a424eb 100644 --- a/crates/core_simd/src/comparisons.rs +++ b/crates/core_simd/src/comparisons.rs @@ -9,12 +9,16 @@ where /// Test if each lane is equal to the corresponding lane in `other`. #[inline] pub fn lanes_eq(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) } } /// Test if each lane is not equal to the corresponding lane in `other`. #[inline] pub fn lanes_ne(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) } } } @@ -27,24 +31,32 @@ where /// Test if each lane is less than the corresponding lane in `other`. #[inline] pub fn lanes_lt(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) } } /// Test if each lane is greater than the corresponding lane in `other`. #[inline] pub fn lanes_gt(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) } } /// Test if each lane is less than or equal to the corresponding lane in `other`. #[inline] pub fn lanes_le(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) } } /// Test if each lane is greater than or equal to the corresponding lane in `other`. #[inline] pub fn lanes_ge(self, other: Self) -> Mask { + // Safety: `self` is a vector, and the result of the comparison + // is always a valid mask. unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) } } } diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index e08e2439b3c..58026042a2f 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -133,6 +133,7 @@ where /// All lanes must be either 0 or -1. #[inline] pub unsafe fn from_int_unchecked(value: Simd) -> Self { + // Safety: the caller must confirm this invariant unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) } } @@ -144,6 +145,7 @@ where #[inline] pub fn from_int(value: Simd) -> Self { assert!(T::valid(value), "all values must be either 0 or -1",); + // Safety: the validity has been checked unsafe { Self::from_int_unchecked(value) } } @@ -160,6 +162,7 @@ where /// `lane` must be less than `LANES`. #[inline] pub unsafe fn test_unchecked(&self, lane: usize) -> bool { + // Safety: the caller must confirm this invariant unsafe { self.0.test_unchecked(lane) } } @@ -170,6 +173,7 @@ where #[inline] pub fn test(&self, lane: usize) -> bool { assert!(lane < LANES, "lane index out of range"); + // Safety: the lane index has been checked unsafe { self.test_unchecked(lane) } } @@ -179,6 +183,7 @@ where /// `lane` must be less than `LANES`. #[inline] pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { + // Safety: the caller must confirm this invariant unsafe { self.0.set_unchecked(lane, value); } @@ -191,6 +196,7 @@ where #[inline] pub fn set(&mut self, lane: usize, value: bool) { assert!(lane < LANES, "lane index out of range"); + // Safety: the lane index has been checked unsafe { self.set_unchecked(lane, value); } diff --git a/crates/core_simd/src/masks/bitmask.rs b/crates/core_simd/src/masks/bitmask.rs index 2689e1a88a8..d3107d21905 100644 --- a/crates/core_simd/src/masks/bitmask.rs +++ b/crates/core_simd/src/masks/bitmask.rs @@ -100,7 +100,14 @@ where #[inline] pub fn to_int(self) -> Simd { + // TODO remove the transmute when rustc is more flexible + // Safety: IntBitMask is the integer equivalent to `self`, and matches the output vector + // lane count. unsafe { + assert_eq!( + core::mem::size_of::< as SupportedLaneCount>::BitMask>(), + core::mem::size_of::< as SupportedLaneCount>::IntBitMask>(), + ); let mask: as SupportedLaneCount>::IntBitMask = core::mem::transmute_copy(&self); intrinsics::simd_select_bitmask(mask, Simd::splat(T::TRUE), Simd::splat(T::FALSE)) @@ -110,11 +117,13 @@ where #[inline] pub unsafe fn from_int_unchecked(value: Simd) -> Self { // TODO remove the transmute when rustc is more flexible - assert_eq!( - core::mem::size_of::< as SupportedLaneCount>::BitMask>(), - core::mem::size_of::< as SupportedLaneCount>::IntBitMask>(), - ); + // Safety: IntBitMask is the integer equivalent to `self`, and matches the output vector + // lane count. unsafe { + assert_eq!( + core::mem::size_of::< as SupportedLaneCount>::BitMask>(), + core::mem::size_of::< as SupportedLaneCount>::IntBitMask>(), + ); let mask: as SupportedLaneCount>::IntBitMask = intrinsics::simd_bitmask(value); Self(core::mem::transmute_copy(&mask), PhantomData) @@ -140,6 +149,7 @@ where where U: MaskElement, { + // Safety: bitmask layout does not depend on the element width unsafe { core::mem::transmute_copy(&self) } } diff --git a/crates/core_simd/src/masks/full_masks.rs b/crates/core_simd/src/masks/full_masks.rs index b653bce05b9..261b20704c4 100644 --- a/crates/core_simd/src/masks/full_masks.rs +++ b/crates/core_simd/src/masks/full_masks.rs @@ -99,12 +99,14 @@ where where U: MaskElement, { + // Safety: masks are simply integer vectors of 0 and -1, and we can cast the element type. unsafe { Mask(intrinsics::simd_cast(self.0)) } } #[cfg(feature = "generic_const_exprs")] #[inline] pub fn to_bitmask(self) -> [u8; LaneCount::::BITMASK_LEN] { + // Safety: IntBitMask is the integer equivalent of the return type. unsafe { // TODO remove the transmute when rustc can use arrays of u8 as bitmasks assert_eq!( @@ -132,6 +134,7 @@ where #[cfg(feature = "generic_const_exprs")] #[inline] pub fn from_bitmask(mut bitmask: [u8; LaneCount::::BITMASK_LEN]) -> Self { + // Safety: IntBitMask is the integer equivalent of the input type. unsafe { // There is a bug where LLVM appears to implement this operation with the wrong // bit order. @@ -160,11 +163,13 @@ where #[inline] pub fn any(self) -> bool { + // Safety: use `self` as an integer vector unsafe { intrinsics::simd_reduce_any(self.to_int()) } } #[inline] pub fn all(self) -> bool { + // Safety: use `self` as an integer vector unsafe { intrinsics::simd_reduce_all(self.to_int()) } } } @@ -187,6 +192,7 @@ where type Output = Self; #[inline] fn bitand(self, rhs: Self) -> Self { + // Safety: `self` is an integer vector unsafe { Self(intrinsics::simd_and(self.0, rhs.0)) } } } @@ -199,6 +205,7 @@ where type Output = Self; #[inline] fn bitor(self, rhs: Self) -> Self { + // Safety: `self` is an integer vector unsafe { Self(intrinsics::simd_or(self.0, rhs.0)) } } } @@ -211,6 +218,7 @@ where type Output = Self; #[inline] fn bitxor(self, rhs: Self) -> Self { + // Safety: `self` is an integer vector unsafe { Self(intrinsics::simd_xor(self.0, rhs.0)) } } } diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs index 2bae414ebfb..a2517714408 100644 --- a/crates/core_simd/src/math.rs +++ b/crates/core_simd/src/math.rs @@ -22,6 +22,7 @@ macro_rules! impl_uint_arith { /// ``` #[inline] pub fn saturating_add(self, second: Self) -> Self { + // Safety: `self` is a vector unsafe { simd_saturating_add(self, second) } } @@ -41,6 +42,7 @@ macro_rules! impl_uint_arith { /// assert_eq!(sat, Simd::splat(0)); #[inline] pub fn saturating_sub(self, second: Self) -> Self { + // Safety: `self` is a vector unsafe { simd_saturating_sub(self, second) } } })+ @@ -68,6 +70,7 @@ macro_rules! impl_int_arith { /// ``` #[inline] pub fn saturating_add(self, second: Self) -> Self { + // Safety: `self` is a vector unsafe { simd_saturating_add(self, second) } } @@ -87,6 +90,7 @@ macro_rules! impl_int_arith { /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0])); #[inline] pub fn saturating_sub(self, second: Self) -> Self { + // Safety: `self` is a vector unsafe { simd_saturating_sub(self, second) } } diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs index 5d7af474caf..9b159c80df6 100644 --- a/crates/core_simd/src/ops.rs +++ b/crates/core_simd/src/ops.rs @@ -209,6 +209,7 @@ macro_rules! impl_op { { type Output = Self; fn neg(self) -> Self::Output { + // Safety: `self` is a vector unsafe { intrinsics::simd_neg(self) } } } @@ -226,6 +227,7 @@ macro_rules! impl_op { #[inline] fn $trait_fn(self, rhs: Self) -> Self::Output { + // Safety: `self` is a vector unsafe { intrinsics::$intrinsic(self, rhs) } @@ -268,6 +270,7 @@ macro_rules! impl_op { { #[inline] fn $assign_trait_fn(&mut self, rhs: Self) { + // Safety: `self` is a vector unsafe { *self = intrinsics::$intrinsic(*self, rhs); } @@ -339,6 +342,8 @@ macro_rules! impl_unsigned_int_ops { .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) { panic!("attempt to divide with overflow"); } + // Safety: `self` is a vector, and the lanes have been checked for + // division by zero and overflow unsafe { intrinsics::simd_div(self, rhs) } } } @@ -362,6 +367,8 @@ macro_rules! impl_unsigned_int_ops { panic!("attempt to divide with overflow"); } let rhs = Self::splat(rhs); + // Safety: `self` is a vector, and the lanes have been checked for + // division by zero and overflow unsafe { intrinsics::simd_div(self, rhs) } } } @@ -429,6 +436,8 @@ macro_rules! impl_unsigned_int_ops { .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) { panic!("attempt to calculate the remainder with overflow"); } + // Safety: `self` is a vector, and the lanes have been checked for + // division by zero and overflow unsafe { intrinsics::simd_rem(self, rhs) } } } @@ -452,6 +461,8 @@ macro_rules! impl_unsigned_int_ops { panic!("attempt to calculate the remainder with overflow"); } let rhs = Self::splat(rhs); + // Safety: `self` is a vector, and the lanes have been checked for + // division by zero and overflow unsafe { intrinsics::simd_rem(self, rhs) } } } @@ -513,6 +524,8 @@ macro_rules! impl_unsigned_int_ops { { panic!("attempt to shift left with overflow"); } + // Safety: `self` is a vector, and the shift argument has been checked for + // overflow unsafe { intrinsics::simd_shl(self, rhs) } } } @@ -531,6 +544,8 @@ macro_rules! impl_unsigned_int_ops { panic!("attempt to shift left with overflow"); } let rhs = Self::splat(rhs); + // Safety: `self` is a vector, and the shift argument has been checked for + // overflow unsafe { intrinsics::simd_shl(self, rhs) } } } @@ -578,6 +593,8 @@ macro_rules! impl_unsigned_int_ops { { panic!("attempt to shift with overflow"); } + // Safety: `self` is a vector, and the shift argument has been checked for + // overflow unsafe { intrinsics::simd_shr(self, rhs) } } } @@ -596,6 +613,8 @@ macro_rules! impl_unsigned_int_ops { panic!("attempt to shift with overflow"); } let rhs = Self::splat(rhs); + // Safety: `self` is a vector, and the shift argument has been checked for + // overflow unsafe { intrinsics::simd_shr(self, rhs) } } } diff --git a/crates/core_simd/src/round.rs b/crates/core_simd/src/round.rs index 09789e11492..b08a22761b7 100644 --- a/crates/core_simd/src/round.rs +++ b/crates/core_simd/src/round.rs @@ -14,6 +14,7 @@ macro_rules! implement { #[must_use = "method returns a new vector and does not mutate the original value"] #[inline] pub fn ceil(self) -> Self { + // Safety: `self` is a vector unsafe { intrinsics::simd_ceil(self) } } @@ -21,6 +22,7 @@ macro_rules! implement { #[must_use = "method returns a new vector and does not mutate the original value"] #[inline] pub fn floor(self) -> Self { + // Safety: `self` is a vector unsafe { intrinsics::simd_floor(self) } } @@ -28,6 +30,7 @@ macro_rules! implement { #[must_use = "method returns a new vector and does not mutate the original value"] #[inline] pub fn round(self) -> Self { + // Safety: `self` is a vector unsafe { intrinsics::simd_round(self) } } @@ -35,6 +38,7 @@ macro_rules! implement { #[must_use = "method returns a new vector and does not mutate the original value"] #[inline] pub fn trunc(self) -> Self { + // Safety: `self` is a vector unsafe { intrinsics::simd_trunc(self) } } @@ -61,6 +65,7 @@ macro_rules! implement { /// * Be representable in the return type, after truncating off its fractional part #[inline] pub unsafe fn to_int_unchecked(self) -> Simd<$int_type, LANES> { + // Safety: the caller must check the invariants unsafe { intrinsics::simd_cast(self) } } @@ -68,6 +73,7 @@ macro_rules! implement { /// not exactly representable. #[inline] pub fn round_from_int(value: Simd<$int_type, LANES>) -> Self { + // Safety: conversion from integer to float vectors is safe unsafe { intrinsics::simd_cast(value) } } } diff --git a/crates/core_simd/src/select.rs b/crates/core_simd/src/select.rs index d976231a03a..d1757793321 100644 --- a/crates/core_simd/src/select.rs +++ b/crates/core_simd/src/select.rs @@ -18,6 +18,7 @@ where { #[inline] fn select(mask: Mask, true_values: Self, false_values: Self) -> Self { + // Safety: `mask` and `Self` are vectors unsafe { intrinsics::simd_select(mask.to_int(), true_values, false_values) } } } diff --git a/crates/core_simd/src/to_bytes.rs b/crates/core_simd/src/to_bytes.rs index 8d9b3e8ff85..b36b1a347b2 100644 --- a/crates/core_simd/src/to_bytes.rs +++ b/crates/core_simd/src/to_bytes.rs @@ -8,12 +8,14 @@ macro_rules! impl_to_bytes { /// Return the memory representation of this integer as a byte array in native byte /// order. pub fn to_ne_bytes(self) -> crate::simd::Simd { + // Safety: transmuting between vectors is safe unsafe { core::mem::transmute_copy(&self) } } /// Create a native endian integer value from its memory representation as a byte array /// in native endianness. pub fn from_ne_bytes(bytes: crate::simd::Simd) -> Self { + // Safety: transmuting between vectors is safe unsafe { core::mem::transmute_copy(&bytes) } } } diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index e353f4352dd..539cfbf3fdd 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -127,7 +127,7 @@ where or: Self, ) -> Self { let enable: Mask = enable & idxs.lanes_lt(Simd::splat(slice.len())); - // SAFETY: We have masked-off out-of-bounds lanes. + // Safety: We have masked-off out-of-bounds lanes. unsafe { Self::gather_select_unchecked(slice, enable, idxs, or) } } @@ -168,7 +168,7 @@ where let base_ptr = crate::simd::ptr::SimdConstPtr::splat(slice.as_ptr()); // Ferris forgive me, I have done pointer arithmetic here. let ptrs = base_ptr.wrapping_add(idxs); - // SAFETY: The ptrs have been bounds-masked to prevent memory-unsafe reads insha'allah + // Safety: The ptrs have been bounds-masked to prevent memory-unsafe reads insha'allah unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } } @@ -220,7 +220,7 @@ where idxs: Simd, ) { let enable: Mask = enable & idxs.lanes_lt(Simd::splat(slice.len())); - // SAFETY: We have masked-off out-of-bounds lanes. + // Safety: We have masked-off out-of-bounds lanes. unsafe { self.scatter_select_unchecked(slice, enable, idxs) } } @@ -259,7 +259,7 @@ where enable: Mask, idxs: Simd, ) { - // SAFETY: This block works with *mut T derived from &mut 'a [T], + // Safety: This block works with *mut T derived from &mut 'a [T], // which means it is delicate in Rust's borrowing model, circa 2021: // &mut 'a [T] asserts uniqueness, so deriving &'a [T] invalidates live *mut Ts! // Even though this block is largely safe methods, it must be exactly this way diff --git a/crates/core_simd/src/vector/float.rs b/crates/core_simd/src/vector/float.rs index c09d0ac84d2..32371d6ad54 100644 --- a/crates/core_simd/src/vector/float.rs +++ b/crates/core_simd/src/vector/float.rs @@ -17,6 +17,7 @@ macro_rules! impl_float_vector { #[inline] pub fn to_bits(self) -> Simd<$bits_ty, LANES> { assert_eq!(core::mem::size_of::(), core::mem::size_of::>()); + // Safety: transmuting vectors is safe unsafe { core::mem::transmute_copy(&self) } } @@ -25,6 +26,7 @@ macro_rules! impl_float_vector { #[inline] pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self { assert_eq!(core::mem::size_of::(), core::mem::size_of::>()); + // Safety: transmuting vectors is safe unsafe { core::mem::transmute_copy(&bits) } } @@ -32,6 +34,7 @@ macro_rules! impl_float_vector { /// equivalently-indexed lane in `self`. #[inline] pub fn abs(self) -> Self { + // Safety: `self` is a float vector unsafe { intrinsics::simd_fabs(self) } } @@ -45,6 +48,7 @@ macro_rules! impl_float_vector { #[cfg(feature = "std")] #[inline] pub fn mul_add(self, a: Self, b: Self) -> Self { + // Safety: `self` is a float vector unsafe { intrinsics::simd_fma(self, a, b) } } @@ -53,6 +57,7 @@ macro_rules! impl_float_vector { #[inline] #[cfg(feature = "std")] pub fn sqrt(self) -> Self { + // Safety: `self` is a float vector unsafe { intrinsics::simd_fsqrt(self) } } diff --git a/crates/core_simd/src/vector/ptr.rs b/crates/core_simd/src/vector/ptr.rs index ac9b98ca031..332989e5c19 100644 --- a/crates/core_simd/src/vector/ptr.rs +++ b/crates/core_simd/src/vector/ptr.rs @@ -21,6 +21,8 @@ where #[inline] #[must_use] pub fn wrapping_add(self, addend: Simd) -> Self { + // Safety: converting pointers to usize and vice-versa is safe + // (even if using that pointer is not) unsafe { let x: Simd = mem::transmute_copy(&self); mem::transmute_copy(&{ x + (addend * mem::size_of::()) }) @@ -47,6 +49,8 @@ where #[inline] #[must_use] pub fn wrapping_add(self, addend: Simd) -> Self { + // Safety: converting pointers to usize and vice-versa is safe + // (even if using that pointer is not) unsafe { let x: Simd = mem::transmute_copy(&self); mem::transmute_copy(&{ x + (addend * mem::size_of::()) }) diff --git a/crates/core_simd/src/vendor.rs b/crates/core_simd/src/vendor.rs index 8c8af43bf13..f555057bf9b 100644 --- a/crates/core_simd/src/vendor.rs +++ b/crates/core_simd/src/vendor.rs @@ -8,6 +8,8 @@ macro_rules! from_transmute { impl core::convert::From<$from> for $to { #[inline] fn from(value: $from) -> $to { + // Safety: transmuting between vectors is safe, but the caller of this macro + // checks the invariants unsafe { core::mem::transmute(value) } } }