diff --git a/library/stdarch/src/lib.rs b/library/stdarch/src/lib.rs index 279f6711d97e..6479f026d577 100644 --- a/library/stdarch/src/lib.rs +++ b/library/stdarch/src/lib.rs @@ -67,32 +67,28 @@ //! to enable a given feature and use the desired intrinsic. //! //! ``` -//! #![feature(cfg_target_feature)] -//! #![feature(target_feature)] +//! # #![feature(cfg_target_feature)] +//! # #![feature(target_feature)] +//! # #[macro_use] +//! # extern crate stdsimd; +//! # fn main() { +//! # if cfg_feature_enabled!("avx2") { +//! // avx2 specific code may be used in this function +//! #[target_feature = "+avx2"] +//! fn and_256() { +//! // avx2 feature specific intrinsics will work here! +//! use stdsimd::vendor::{__m256i, _mm256_and_si256}; //! -//! #[macro_use] -//! extern crate stdsimd; +//! let a = __m256i::splat(5); +//! let b = __m256i::splat(3); //! -//! fn main() { -//! if cfg_feature_enabled!("avx2") { +//! let got = unsafe { _mm256_and_si256(a, b) }; //! -//! // avx2 will work. It is safe to use avx2 specific code here. -//! #[target_feature = "+avx2"] -//! fn and_256() { -//! // avx2 feature specific intrinsics will work here! -//! use stdsimd::vendor::{__m256i, _mm256_and_si256}; -//! -//! let a = __m256i::splat(5); -//! let b = __m256i::splat(3); -//! let got = unsafe { _mm256_and_si256(a, b) }; -//! assert_eq!(got, __m256i::splat(1)); -//! } -//! -//! and_256(); -//! } else { -//! println!("avx2 intrinsics will not work, they may generate SIGILL"); -//! } +//! assert_eq!(got, __m256i::splat(1)); //! } +//! # and_256(); +//! # } +//! # } //! ``` //! //! # Status diff --git a/library/stdarch/src/x86/sse42.rs b/library/stdarch/src/x86/sse42.rs index 5b9a3ecde7b6..9145398bd76c 100644 --- a/library/stdarch/src/x86/sse42.rs +++ b/library/stdarch/src/x86/sse42.rs @@ -58,7 +58,9 @@ macro_rules! call { } /// Compare packed strings with implicit lengths in `a` and `b` using the -/// control in `imm8`, and return the generated index. +/// control in `imm8`, and return the generated index. Similar to [`_mm_cmpestri`] +/// with the excception that [`_mm_cmpestri`] requires the lengths of `a` and +/// `b` to be explicitly specified. /// /// # Control modes /// @@ -87,6 +89,8 @@ macro_rules! call { /// /// # Examples /// +/// Find a substring using [`_SIDD_CMP_EQUAL_ORDERED`] +/// /// ``` /// # #![feature(cfg_target_feature)] /// # #![feature(target_feature)] @@ -126,6 +130,89 @@ macro_rules! call { /// # } /// ``` /// +/// The `_mm_cmpistri` intrinsic may also be used to find the existance of +/// one or more of a given set of characters in the haystack. +/// +/// ``` +/// # #![feature(cfg_target_feature)] +/// # #![feature(target_feature)] +/// # +/// # #[macro_use] extern crate stdsimd; +/// # +/// # fn main() { +/// # if cfg_feature_enabled!("sse4.2") { +/// # #[target_feature = "+sse4.2"] +/// # fn worker() { +/// use stdsimd::simd::u8x16; +/// use stdsimd::vendor::{__m128i, _mm_cmpistri, _SIDD_CMP_EQUAL_ANY}; +/// +/// // Ensure your input is 16 byte aligned +/// let password = b"hunter2\0\0\0\0\0\0\0\0\0"; +/// let special_chars = b"!@#$%^&*()[]:;<>"; +/// +/// // Load the input +/// let a = __m128i::from(u8x16::load(special_chars, 0)); +/// let b = __m128i::from(u8x16::load(password, 0)); +/// +/// // Use _SIDD_CMP_EQUAL_ANY to find the index of any bytes in b +/// let idx = unsafe { +/// _mm_cmpistri(a, b, _SIDD_CMP_EQUAL_ANY) +/// }; +/// +/// if idx < 16 { +/// println!("Congrats! Your password contains a special character"); +/// # panic!("{:?} does not contain a special character", password); +/// } else { +/// println!("Your password should contain a special character"); +/// } +/// # } +/// # worker(); +/// # } +/// # } +/// ``` +/// +/// Working with 16-bit characters. +/// +/// ``` +/// # #![feature(cfg_target_feature)] +/// # #![feature(target_feature)] +/// # +/// # #[macro_use] extern crate stdsimd; +/// # +/// # fn main() { +/// # if cfg_feature_enabled!("sse4.2") { +/// # #[target_feature = "+sse4.2"] +/// # fn worker() { +/// use stdsimd::simd::u16x8; +/// use stdsimd::vendor::{__m128i, _mm_cmpistri}; +/// use stdsimd::vendor::{_SIDD_UWORD_OPS, _SIDD_CMP_EQUAL_EACH}; +/// +/// # let mut some_utf16_words = [0u16; 8]; +/// # let mut more_utf16_words = [0u16; 8]; +/// # '❤'.encode_utf16(&mut some_utf16_words); +/// # '𝕊'.encode_utf16(&mut more_utf16_words); +/// // Load the input +/// let a = __m128i::from(u16x8::load(&some_utf16_words, 0)); +/// let b = __m128i::from(u16x8::load(&more_utf16_words, 0)); +/// +/// // Specify _SIDD_UWORD_OPS to compare words instead of bytes, and +/// // use _SIDD_CMP_EQUAL_EACH to compare the two strings. +/// let idx = unsafe { +/// _mm_cmpistri(a, b, _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH) +/// }; +/// +/// if idx == 0 { +/// println!("16-bit unicode strings were equal!"); +/// # panic!("Strings should not be equal!") +/// } else { +/// println!("16-bit unicode strings were not equal!"); +/// } +/// # } +/// # worker(); +/// # } +/// # } +/// ``` +/// /// [`_SIDD_UBYTE_OPS`]: constant._SIDD_UBYTE_OPS.html /// [`_SIDD_UWORD_OPS`]: constant._SIDD_UWORD_OPS.html /// [`_SIDD_SBYTE_OPS`]: constant._SIDD_SBYTE_OPS.html @@ -138,6 +225,7 @@ macro_rules! call { /// [`_SIDD_NEGATIVE_POLARITY`]: constant._SIDD_NEGATIVE_POLARITY.html /// [`_SIDD_LEAST_SIGNIFICANT`]: constant._SIDD_LEAST_SIGNIFICANT.html /// [`_SIDD_MOST_SIGNIFICANT`]: constant._SIDD_MOST_SIGNIFICANT.html +/// [`_mm_cmpestri`]: fn._mm_cmpestri.html #[inline(always)] #[target_feature = "+sse4.2"] #[cfg_attr(test, assert_instr(pcmpistri, imm8 = 0))] @@ -255,7 +343,87 @@ macro_rules! call { } /// Compare packed strings `a` and `b` with lengths `la` and `lb` using the -/// control in `imm8`, and return the generated index. +/// control in `imm8`, and return the generated index. Similar to [`_mm_cmpistri`] +/// with the excception that [`_mm_cmpistri`] implicityly determines the length of +/// `a` and `b`. +/// +/// # Control modes +/// +/// The control specified by `imm8` may be one or more of the following. +/// +/// ## Data size and signedness +/// +/// - [`_SIDD_UBYTE_OPS`] - Default +/// - [`_SIDD_UWORD_OPS`] +/// - [`_SIDD_SBYTE_OPS`] +/// - [`_SIDD_SWORD_OPS`] +/// +/// ## Comparison options +/// - [`_SIDD_CMP_EQUAL_ANY`] - Default +/// - [`_SIDD_CMP_RANGES`] +/// - [`_SIDD_CMP_EQUAL_EACH`] +/// - [`_SIDD_CMP_EQUAL_ORDERED`] +/// +/// ## Result polarity +/// - [`_SIDD_POSITIVE_POLARITY`] - Default +/// - [`_SIDD_NEGATIVE_POLARITY`] +/// +/// ## Bit returned +/// - [`_SIDD_LEAST_SIGNIFICANT`] - Default +/// - [`_SIDD_MOST_SIGNIFICANT`] +/// +/// # Examples +/// +/// ``` +/// # #![feature(cfg_target_feature)] +/// # #![feature(target_feature)] +/// # +/// # #[macro_use] extern crate stdsimd; +/// # +/// # fn main() { +/// # if cfg_feature_enabled!("sse4.2") { +/// # #[target_feature = "+sse4.2"] +/// # fn worker() { +/// +/// use stdsimd::simd::u8x16; +/// use stdsimd::vendor::{__m128i, _mm_cmpestri, _SIDD_CMP_EQUAL_ORDERED}; +/// +/// // The string we want to find a substring in +/// let haystack = b"Split \r\n\t line "; +/// +/// // The string we want to search for with some +/// // extra bytes we do not want to search for. +/// let needle = b"\r\n\t ignore this "; +/// +/// let a = __m128i::from(u8x16::load(needle, 0)); +/// let b = __m128i::from(u8x16::load(haystack, 0)); +/// +/// // Note: We explicitly specify we only want to search `b` for the +/// // first 3 characters of a. +/// let idx = unsafe { +/// _mm_cmpestri(a, 3, b, 15, _SIDD_CMP_EQUAL_ORDERED) +/// }; +/// +/// assert_eq!(idx, 6); +/// # } +/// # worker(); +/// # } +/// # } +/// ``` +/// +/// [`_SIDD_UBYTE_OPS`]: constant._SIDD_UBYTE_OPS.html +/// [`_SIDD_UWORD_OPS`]: constant._SIDD_UWORD_OPS.html +/// [`_SIDD_SBYTE_OPS`]: constant._SIDD_SBYTE_OPS.html +/// [`_SIDD_SWORD_OPS`]: constant._SIDD_SWORD_OPS.html +/// [`_SIDD_CMP_EQUAL_ANY`]: constant._SIDD_CMP_EQUAL_ANY.html +/// [`_SIDD_CMP_RANGES`]: constant._SIDD_CMP_RANGES.html +/// [`_SIDD_CMP_EQUAL_EACH`]: constant._SIDD_CMP_EQUAL_EACH.html +/// [`_SIDD_CMP_EQUAL_ORDERED`]: constant._SIDD_CMP_EQUAL_ORDERED.html +/// [`_SIDD_POSITIVE_POLARITY`]: constant._SIDD_POSITIVE_POLARITY.html +/// [`_SIDD_NEGATIVE_POLARITY`]: constant._SIDD_NEGATIVE_POLARITY.html +/// [`_SIDD_LEAST_SIGNIFICANT`]: constant._SIDD_LEAST_SIGNIFICANT.html +/// [`_SIDD_MOST_SIGNIFICANT`]: constant._SIDD_MOST_SIGNIFICANT.html +/// [`_mm_cmpistri`]: fn._mm_cmpistri.html #[inline(always)] #[target_feature = "+sse4.2"] #[cfg_attr(test, assert_instr(pcmpestri, imm8 = 0))]