_mm256_blendv_pd()
查看位置63,127,191和255中的位。是否有一种有效的方法将uint8_t
的4个低位分散到AVX寄存器的这些位置?
或者,是否有一种有效的方式来广播这些位,以便像_mm256_cmp_pd()
的结果一样,每个位在AVX寄存器的相应64位组件中重复?
指令集为AVX2(Ryzen CPU,如果需要其他功能)。
答案 0 :(得分:2)
最有效的方法是使用包含16个256位条目的查找向量,由uint-8索引。
答案 1 :(得分:2)
显而易见的解决方案:将这4位用作查找表的索引。你已经知道了,所以让我们尝试其他的东西。
基于变量移位的方法:将该字节广播到每个qword中,然后将其向左移动{63,62,61,60},在msb中排列正确的位。未经测试,如下所示:
_mm256_sllv_epi64(_mm256_set1_epi64x(mask), _mm256_set_epi64x(63, 62, 61, 60))
作为奖励,因为负载不依赖于面罩,所以它可以从环中抬起。
这对于Ryzen来说不一定是个好主意,内存中的256位加载比单独vpsllvq
本身的吞吐量更高(与Ryzen上的大多数256b操作相比,这是2μs),但是这里我们还有vmovq
(如果该字节不是来自向量寄存器)和宽vpbroadcastq
(再次为2μs)。
根据具体情况,可能值得做或不做。这取决于。
答案 2 :(得分:2)
假设uint8_t
存在于通用寄存器中;方法是:
PDEP
将四位转换为四位(最高位)所以我提出了两个版本 - 一个带内存,另一个没有:
接近记忆:
.data
; Always use the highest bytes of a QWORD as target / 128 means 'set ZERO'
ddqValuesDistribution: .byte 3,128,128,128,128,128,128,128, 2,128,128,128,128,128,128,128, 1,128,128,128,128,128,128,128, 0,128,128,128,128,128,128,128
.code
; Input value in lower 4 bits of EAX
mov edx, 0b10000000100000001000000010000000
pdep eax, eax, edx
vmovd xmm0, eax
vpshufb ymm0, ymm0, ymmword ptr [ddqValuesDistribution]
这一个在Haswell和Skylake上以5 uOps出现。
没有记忆变量的方法(由于@Peter Cordes而得到改善):
mov edx, 0b10000000100000001000000010000000
pdep eax, eax, edx
vmovd xmm0, eax
vpmovsxbq ymm0, xmm0
这个在Haswell和Skylake(!)上以4 uOps出现,可以通过将EDX中的蒙版移动到变量来进一步改进。
输出与第一个版本不同(所有输出与仅最高位设置)。