是否有一个内在函数将__m128i向量的最后n个字节清零?

问题描述

鉴于callback: async (confirm) => { if (confirm) { let res = await this.$auth.logout() } } ,我想将n向量的最后n个字节清零。

例如,考虑以下__m128i向量:

__m128i

将最后11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111个字节清零后,向量应如下所示:

n = 4

是否有SSE内在函数可以做到这一点(通过接受11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00000000 00000000 00000000向量和__128i作为参数)?

解决方法

有许多不依赖于AVX512的选项。例如:

未对齐负载

char mask[32] = { 0,-1,-1};

__m128i zeroLowestNBytes(__m128i x,uint32_t n)
{
    __m128i m = _mm_loadu_si128((__m128i*)&mask[16 - n]);
    return _mm_and_si128(x,m);
}

使用AVX,加载可以成为vpand的内存操作数。如果没有AVX,也可以使用movdqupand

不对齐的负载通常不是问题,除非它越过4K边界。如果您可以使mask对齐32,则该问题将消失。负载仍将不对齐,但不会碰到该特定的边缘情况。

nuint32_t,以避免符号扩展。

广播和比较

__m128i zeroLowestNBytes(__m128i x,int n)
{
    __m128i threshold = _mm_set1_epi8(n);
    __m128i index = _mm_set_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);
    return _mm_andnot_si128(_mm_cmpgt_epi8(threshold,index),x);
}

这避免了未对齐的负载,但这并不重要。更重要的是,它避免了“依赖于输入的负载”:在未对齐负载的版本中,负载取决于n。在此版本中,负载独立于n。例如,如果内联此函数,则允许编译器将其提升到循环之外。它还使乱序执行有更大的自由度,可以在计算n之前尽早开始加载。

另一面是,它基本上需要AVX2或SSSE3才能实现_mm_set1_epi8(n)。同样,这通常会花费更多指令,这可能会降低吞吐量。延迟应该更好,因为“主链”中没有负载(有负载,但负担很重,不会将延迟添加到计算延迟中。)

,

您应该能够通过使用_mm_mask_set1_epi8内在函数在向量的末尾将零“广播”到所需的字节来实现所需的结果。

__m128i _mm_mask_set1_epi8 (__m128i src,__mmask16 k,char a)
  • src是您的__m128i向量
  • __mmask16n构造为(1 << n) - 1,即在掩码的末尾加上n
  • char a为零

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...