我用avx-512指令编写了strlen函数,这是我的源代码
size_t avx512_strlen(const char * s) {
__m512i vec0, vec1;
unsigned long long mask;
const char * ptr = s;
vec0 = _mm512_setzero_epi32();
while (1) {
vec1 = _mm512_loadu_si512(s);
mask = _mm512_cmpeq_epi8_mask(vec0, vec1);
if(mask != 0) {
mask = __builtin_ctz(mask);
return (s-ptr) + mask;
}
s += 64;
}
return s-ptr;
}
'__ builtin_ctz(mask)的值存在问题,并且返回的值不正确。实际上,此函数无法在最后一次检查中计算空终止符(0x00)的位置
例如,我有这个字符串
char str[] = "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE";
该字符串的长度为(360),但此函数返回(352),问题出在'__builtin_ctz'部分。在执行“ __builtin_ctz”之前,提供的遮罩是正确的,它是
0001110100010001000100010000000000000000000000000000000000000000
在最后一次检查中,我们检查了320个字符,并且__builtin_ctz必须返回(40)(如您在掩码中所看到的,我们将40个零计数到第一个“ 1”,并且假设掩码正确,并且'__builtin_ctz'认为它是错误的!
什么问题?
__builtin_ctz
在unsigned int
上运行,在任何x86平台上可能都是32位。同时,在任何x86平台上unsigned long long
可能都是64位。因此,您的遮罩在此行被截断:
mask = __builtin_ctz(mask);
由于低32位全为零,所以the result is undefined (per GCC):
返回x中从最低有效位开始的尾随0位的数目。如果x为0,则结果不确定。
(尽管未定义,352 - 320 = 32
是]对于“ 32位零整数中的尾随0位的数目。”的合理答案。]
您可能打算改用__builtin_ctzll(mask)
。那应该给您正确的计数。
__builtin_ctz
在unsigned int
上运行,在任何x86平台上可能都是32位。同时,在任何x86平台上unsigned long long
可能都是64位。因此,您的遮罩在此行被截断:
mask = __builtin_ctz(mask);
由于低32位全为零,所以the result is undefined (per GCC):
返回x中从最低有效位开始的尾随0位的数目。如果x为0,则结果不确定。
(尽管未定义,352 - 320 = 32
是]对于“ 32位零整数中的尾随0位的数目。”的合理答案。]
您可能打算改用__builtin_ctzll(mask)
。那应该给您正确的计数。