可以使用 `_mm256_movemask_ps` 代替未定义的 `_mm256_movemask_epi32` 吗?
Can `_mm256_movemask_ps` be used instead of undefined `_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 上它被解码为许多 micro-ops 并且需要将近 20 CPU 个周期。
无法在 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 上它被解码为许多 micro-ops 并且需要将近 20 CPU 个周期。