可以使用“ _mm256_movemask_ps”代替未定义的“ _mm256_movemask_epi32”吗?

问题描述

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周期。