From c1da3bad76ec6dbee66e3eaabf979a0513a9d253 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Wed, 4 Oct 2017 05:15:39 -0400 Subject: [PATCH] [Docs] Improve documentation (#87) - Add "How to write and example" section to CONTRIBUTING.md - Add a basic example using `target_feature` to the main page - Improve documentation of SSE 4.2 - Improve documentation of constants - Improve documentation of _mm_cmpistri --- library/stdarch/CONTRIBUTING.md | 54 ++++++++++++++++-- library/stdarch/src/lib.rs | 32 +++++++++++ library/stdarch/src/x86/sse42.rs | 97 +++++++++++++++++++++++++++++--- 3 files changed, 169 insertions(+), 14 deletions(-) diff --git a/library/stdarch/CONTRIBUTING.md b/library/stdarch/CONTRIBUTING.md index ce6f3da8f203..2ca8604f17b2 100644 --- a/library/stdarch/CONTRIBUTING.md +++ b/library/stdarch/CONTRIBUTING.md @@ -24,13 +24,57 @@ particularly use some help. You may be most interested in [#40][vendor], implementing all vendor intrinsics on x86. That issue's got some good pointers about where to get started! +If you've got general questions feel free to [join us on gitter][gitter] and ask +around! Feel free to ping either @BurntSushi or @alexcrichton with questions. + +[gitter]: https://gitter.im/rust-impl-period/WG-libs-simd + +# How to write examples for stdsimd intrinsics + +There are a few features that must be enabled for the given intrinsic to work +properly and the example must only be run by `cargo test --doc` when the feature +is supported by the CPU. As a result, the default `fn main` that is generated by +`rustdoc` will not work (in most cases). Consider using the following as a guide +to ensure your example works as expected. + +```rust +/// # // We need cfg_target_feature to ensure the example is only +/// # // run by `cargo test --doc` when the CPU supports the feature +/// # #![feature(cfg_target_feature)] +/// # // We need target_feature for the intrinsic to work +/// # #![feature(target_feature)] +/// # +/// # // rustdoc by default uses `extern crate stdsimd`, but we need the +/// # // `#[macro_use]` +/// # #[macro_use] extern crate stdsimd; +/// # +/// # // The real main function +/// # fn main() { +/// # // Only run this if `` is supported +/// # if cfg_feature_enabled!("") { +/// # // Create a `worker` function that will only be run if the target feature +/// # // is supported and ensure that `target_feature` is enabled for your worker +/// # // function +/// # #[target_feature = "+"] +/// # fn worker() { +/// +/// // Write your example here. Feature specific intrinsics will work here! Go wild! +/// +/// # } +/// # worker(); +/// # } +/// # } +``` + +If some of the above syntax does not look familiar, the [Documentation as tests] section +of the [Rust Book] describes the `rustdoc` syntax quite well. As always, feel free +to [join us on gitter][gitter] and ask us if you hit any snags, and thank you for helping +to improve the documentation of `stdsimd`! + [new]: https://github.com/rust-lang-nursery/stdsimd/issues/new [issues]: https://github.com/rust-lang-nursery/stdsimd/issues [help]: https://github.com/rust-lang-nursery/stdsimd/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22 [impl]: https://github.com/rust-lang-nursery/stdsimd/issues?q=is%3Aissue+is%3Aopen+label%3Aimpl-period [vendor]: https://github.com/rust-lang-nursery/stdsimd/issues/40 - -If you've got general questions feel free to [join us on gitter][gitter] and ask -around! Feel free to ping either @BurntSushi or @alexcrichton with questions. - -[gitter]: https://gitter.im/rust-impl-period/WG-libs-simd +[Documentation as tests]: https://doc.rust-lang.org/book/first-edition/documentation.html#documentation-as-tests +[Rust Book]: https://doc.rust-lang.org/book/first-edition diff --git a/library/stdarch/src/lib.rs b/library/stdarch/src/lib.rs index 66676c5ba410..17433c294c61 100644 --- a/library/stdarch/src/lib.rs +++ b/library/stdarch/src/lib.rs @@ -63,6 +63,38 @@ //! } //! ``` //! +//! After verifying that a specified feature is available, use `target_feature` +//! to enable a given feature and use the desired intrinsic. +//! +//! ``` +//! #![feature(cfg_target_feature)] +//! #![feature(target_feature)] +//! +//! #[macro_use] +//! extern crate stdsimd; +//! +//! fn main() { +//! if cfg_feature_enabled!("avx2") { +//! +//! // 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"); +//! } +//! } +//! ``` +//! //! # Status //! //! This crate is intended for eventual inclusion into the standard library, but diff --git a/library/stdarch/src/x86/sse42.rs b/library/stdarch/src/x86/sse42.rs index 4697d7c58fa7..5b9a3ecde7b6 100644 --- a/library/stdarch/src/x86/sse42.rs +++ b/library/stdarch/src/x86/sse42.rs @@ -4,7 +4,7 @@ use stdsimd_test::assert_instr; use v128::*; use x86::__m128i; -/// String contains unsigned 8-bit characters +/// String contains unsigned 8-bit characters *(Default)* pub const _SIDD_UBYTE_OPS: i8 = 0b00000000; /// String contains unsigned 16-bit characters pub const _SIDD_UWORD_OPS: i8 = 0b00000001; @@ -13,16 +13,16 @@ pub const _SIDD_SBYTE_OPS: i8 = 0b00000010; /// String contains unsigned 16-bit characters pub const _SIDD_SWORD_OPS: i8 = 0b00000011; -/// For each character in `a`, find if it is in `b` +/// For each character in `a`, find if it is in `b` *(Default)* pub const _SIDD_CMP_EQUAL_ANY: i8 = 0b00000000; /// For each character in `a`, determine if `b[0] <= c <= b[1] or b[1] <= c <= b[2]...` pub const _SIDD_CMP_RANGES: i8 = 0b00000100; -/// String equality +/// The strings defined by `a` and `b` are equal pub const _SIDD_CMP_EQUAL_EACH: i8 = 0b00001000; -/// Substring search +/// Search for the defined substring in the target pub const _SIDD_CMP_EQUAL_ORDERED: i8 = 0b00001100; -/// Do not negate results +/// Do not negate results *(Default)* pub const _SIDD_POSITIVE_POLARITY: i8 = 0b00000000; /// Negate results pub const _SIDD_NEGATIVE_POLARITY: i8 = 0b00010000; @@ -31,14 +31,14 @@ pub const _SIDD_MASKED_POSITIVE_POLARITY: i8 = 0b00100000; /// Negate results only before the end of the string pub const _SIDD_MASKED_NEGATIVE_POLARITY: i8 = 0b00110000; -/// Index only: return the least significant bit +/// **Index only**: return the least significant bit *(Default)* pub const _SIDD_LEAST_SIGNIFICANT: i8 = 0b00000000; -/// Index only: return the most significant bit +/// **Index only**: return the most significant bit pub const _SIDD_MOST_SIGNIFICANT: i8 = 0b01000000; -/// Mask only: return the bit mask +/// **Mask only**: return the bit mask pub const _SIDD_BIT_MASK: i8 = 0b00000000; -/// Mask only: return the byte mask +/// **Mask only**: return the byte mask pub const _SIDD_UNIT_MASK: i8 = 0b01000000; /// Compare packed strings with implicit lengths in `a` and `b` using the @@ -59,6 +59,85 @@ pub unsafe fn _mm_cmpistrm( /// Compare packed strings with implicit lengths in `a` and `b` using the /// control in `imm8`, and return the generated index. +/// +/// # 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_cmpistri, _SIDD_CMP_EQUAL_ORDERED}; +/// +/// let haystack = b"This is a long string of text data\r\n\tthat extends multiple lines"; +/// let needle = b"\r\n\t\0\0\0\0\0\0\0\0\0\0\0\0\0"; +/// +/// let a = __m128i::from(u8x16::load(needle, 0)); +/// let hop = 16; +/// let mut indexes = Vec::new(); +/// +/// // Chunk the haystack into 16 byte chunks and find +/// // the first "\r\n\t" in the chunk. +/// for (i, chunk) in haystack.chunks(hop).enumerate() { +/// let b = __m128i::from(u8x16::load(chunk, 0)); +/// let idx = unsafe { +/// _mm_cmpistri(a, b, _SIDD_CMP_EQUAL_ORDERED) +/// }; +/// if idx != 16 { +/// indexes.push((idx as usize) + (i * hop)); +/// } +/// } +/// assert_eq!(indexes, vec![34]); +/// # } +/// # 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 #[inline(always)] #[target_feature = "+sse4.2"] #[cfg_attr(test, assert_instr(pcmpistri, imm8 = 0))]