问题描述
在https://software.intel.com/sites/landingpage/IntrinsicsGuide中找不到_mm256_movemask_epi8
所需的DWORD副本,所以我的问题是是否使用AVX float _mm256_movemask_ps
是允许的,否则怎么办?
据我了解,_mm256_movemask_epi8
可以完成这项工作,但最终的掩码是32位,而我需要将掩码设置为8位(对于8个DWORD中的每一个都需要一个位)。
我努力奋斗的片段是这样:
} else { // Below: haystack >=128; needle >=4; VECTOR
// Stage 1: SSE2 or AVX2 i.e. 16 or 32 strides.
// Stage 2: Dealing with the eventual remainder.
// The main idea: Stressing the registers as it was done in Quadruplet (the above fastest etude) - outperforms Stephen R. van den Berg's strstr at http://www.scs.stanford.edu/histar/src/pkg/uclibc/libc/string/generic/strstr.c
// __m256i _mm256_cmpeq_epi32 (__m256i a,__m256i b) needs AVX2; the more attractive __mmask8 _mm256_cmpeq_epi32_mask (__m256i a,__m256i b) needs AVX512??
// Pattern: "Linus Torvalds"
// Order4: [ ] skip 32 if not a single occurrence of 'alds' within YMM + (Order - 1) = 32 + 3 = 35 bytes window:
// haystack: "otto.......................Torvalds"
// YMM haystackVector1: "otto.......................Torva"
// YMM haystackVector2: "tto.......................Torval"
// YMM haystackVector3: "to.......................Torvald"
// YMM haystackVector4: "o.......................Torvalds"
// YMM Vector1: "aldsaldsaldsaldsaldsaldsaldsalds"
//
// Mask1=(haystackVector1 eqd Vector1): 0 0 0 0 0 0 0 0 ! 8bit !
// Mask2=(haystackVector2 eqd Vector1): 0 0 0 0 0 0 0 0 ! 8bit !
// Mask3=(haystackVector3 eqd Vector1): 0 0 0 0 0 0 0 0 ! 8bit !
// Mask4=(haystackVector4 eqd Vector1): 0 0 0 0 0 0 0 1 ! 8bit !
// Result=(Mask1 OR Mask2 OR Mask3 OR Mask4): 0 0 0 0 0 0 0 1 ! 8bit !
size_t YMMchunks = cbTarget/32 -1; // in here,ensured at least 4 chunks; in order to avoid past haystack YMM reads - decrease 1 chunk and finish with Scalar_Quadruplet
const __m256i last4 = _mm256_set1_epi32(pbPattern[cbPattern - 1 -3]);
for (size_t i = 0; i < YMMchunks; i += 32) {
const __m256i haystackVector1 = _mm256_loadu_si256((const __m256i*)(pbTarget + i + 0));
const __m256i haystackVector2 = _mm256_loadu_si256((const __m256i*)(pbTarget + i + 1));
const __m256i haystackVector3 = _mm256_loadu_si256((const __m256i*)(pbTarget + i + 2));
const __m256i haystackVector4 = _mm256_loadu_si256((const __m256i*)(pbTarget + i + 3));
const __m256i EQD1 = _mm256_cmpeq_epi32(haystackVector1,last4);
const __m256i EQD2 = _mm256_cmpeq_epi32(haystackVector2,last4);
const __m256i EQD3 = _mm256_cmpeq_epi32(haystackVector3,last4);
const __m256i EQD4 = _mm256_cmpeq_epi32(haystackVector4,last4);
const __m256i FinalVector12 = _mm256_or_si256(EQD1,EQD2);
const __m256i FinalVector34 = _mm256_or_si256(EQD3,EQD4);
uint32_t mask = _mm256_movemask_epi8(_mm256_or_si256(FinalVector12,FinalVector34));
//uint8_t mask = _mm256_movemask_ps(_mm256_or_si256(FinalVector12,FinalVector34)); //AVX is 8x4float _mm256_movemask_ps,Couldn't find _mm256_movemask_epi32 ! Is it allowed?
// ...
}
// ...
} //if (cbTarget<128) {
解决方法
这很好,您只需要_mm256_castsi256_ps
。对于64位整数相同,将其转换为双精度向量并使用_mm256_movemask_pd
。
另一种选择,如果您有BMI2 support,则可以使用_mm256_movemask_epi8
,然后使用_pext_u32
和掩码0x88888888
丢弃不需要的位并打包其余8位写入字节。但是,该指令仅在Intel上是快速的,在AMD上它已被解码为许多微操作,并且需要近20个CPU周期。