Function _mm_cmpistri

#[target_feature(enable = "sse4.2")]
pub fn _mm_cmpistri(a: __m128i, b: __m128i, IMM8: i32) -> i32

Compares packed strings with implicit lengths in a and b using the control in IMM8 and return the generated index. Similar to _mm_cmpestri with the exception that _mm_cmpestri requires the lengths of a and b to be explicitly specified.

Control modes

The control specified by IMM8 may be one or more of the following.

Data size and signedness

Comparison options

Result polarity

Bit returned

Examples

Finds a substring using _SIDD_CMP_EQUAL_ORDERED

#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

# fn main() {
#     if is_x86_feature_detected!("sse4.2") {
#         #[target_feature(enable = "sse4.2")]
#         unsafe fn worker() {
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 = unsafe { _mm_loadu_si128(needle.as_ptr() as *const _) };
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 = unsafe { _mm_loadu_si128(chunk.as_ptr() as *const _) };
    let idx = _mm_cmpistri(a, b, _SIDD_CMP_EQUAL_ORDERED);
    if idx != 16 {
        indexes.push((idx as usize) + (i * hop));
    }
}
assert_eq!(indexes, vec![34]);
#         }
#         unsafe { worker(); }
#     }
# }

The _mm_cmpistri intrinsic may also be used to find the existence of one or more of a given set of characters in the haystack.

#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

# fn main() {
#     if is_x86_feature_detected!("sse4.2") {
#         #[target_feature(enable = "sse4.2")]
#         unsafe fn worker() {
// 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 = unsafe { _mm_loadu_si128(special_chars.as_ptr() as *const _) };
let b = unsafe { _mm_loadu_si128(password.as_ptr() as *const _) };

// Use _SIDD_CMP_EQUAL_ANY to find the index of any bytes in b
let idx = _mm_cmpistri(a.into(), b.into(), _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");
}
#         }
#         unsafe { worker(); }
#     }
# }

Finds the index of the first character in the haystack that is within a range of characters.

#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

# fn main() {
#     if is_x86_feature_detected!("sse4.2") {
#         #[target_feature(enable = "sse4.2")]
#         unsafe fn worker() {
# let b = b":;<=>?@[\\]^_`abc";
# let b = unsafe { _mm_loadu_si128(b.as_ptr() as *const _) };

// Specify the ranges of values to be searched for [A-Za-z0-9].
let a = b"AZaz09\0\0\0\0\0\0\0\0\0\0";
let a = unsafe { _mm_loadu_si128(a.as_ptr() as *const _) };

// Use _SIDD_CMP_RANGES to find the index of first byte in ranges.
// Which in this case will be the first alpha numeric byte found
// in the string.
let idx = _mm_cmpistri(a, b, _SIDD_CMP_RANGES);

if idx < 16 {
    println!("Found an alpha numeric character");
    # assert_eq!(idx, 13);
} else {
    println!("Did not find an alpha numeric character");
}
#         }
#         unsafe { worker(); }
#     }
# }

Working with 16-bit characters.

#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

# fn main() {
#     if is_x86_feature_detected!("sse4.2") {
#         #[target_feature(enable = "sse4.2")]
#         unsafe fn worker() {
# 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 = unsafe { _mm_loadu_si128(some_utf16_words.as_ptr() as *const _) };
let b = unsafe { _mm_loadu_si128(more_utf16_words.as_ptr() as *const _) };

// Specify _SIDD_UWORD_OPS to compare words instead of bytes, and
// use _SIDD_CMP_EQUAL_EACH to compare the two strings.
let idx = _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!");
}
#         }
#         unsafe { worker(); }
#     }
# }

Intel's documentation