有4位,如何为AVX寄存器产生口罩
Having 4 bits, how to produce a mask for AVX register?
_mm256_blendv_pd()
查看位置63、127、191和255的位置。是否有一种有效的方法将uint8_t
的4个较低位散射到AVX寄存器的这些位置中?
另外,是否有一种有效的方法来广播这些位,因此像_mm256_cmp_pd()
的结果一样,每个位在AVX寄存器的相应64位组件中重复?
指令集为AVX2(如果需要其他功能,则Ryzen CPU)。
假设uint8_t
在通用寄存器中存在;方法是:
- 使用
PDEP
将四位转换为四个字节(最高位) - 将四个字节从32位GPR传输到YMM寄存器的低部分
- 将值置于适当的位置(位63、127、191、255)
所以我想出了两个版本 - 一个带有内存的版本,另一个没有:
与内存接近:
.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,可以通过将Mask移动到EDX中,从而进一步改善。
输出不同于第一个版本(所有版本与最高位设置)。
最有效的方法是使用包含16位256位条目的查找向量,由UINT-8索引。
明显的解决方案:将这些4位用作索引中的索引。您已经知道这一点,所以让我们尝试一下。
基于变量的方法:将字节广播到每个QWOWS中,然后将其向左移动{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 µ,但在这里我们也有vmovq
(如果该字节不是来自矢量寄存器)和宽vpbroadcastq
(再次2 µOPS)。
取决于上下文,可能值得做与否。这取决于
相关文章:
- 本质:使用__128寄存器
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 在模拟器中使用并集来模拟CPU寄存器有多合适
- 使用英特尔 PIN 修改寄存器
- AVX 指令中寄存器和指针之间的客观差异
- 如何确定我的处理器有多少个 AVX 寄存器?
- 除非使用某些寄存器,否则函数挂钩会崩溃
- 寄存器上的管道计算
- 其中关于内存和寄存器的左值和右值
- 有没有办法强制C++编译器将变量存储在寄存器中?
- "变量":函数中函数作用域不允许初始化的自动或寄存器变量'naked'
- Atmel Studio:返回一个包含数组的寄存器
- 使用 AVX 对两个 zmm(512 位)寄存器进行异或运算
- 在英特尔x86体系结构上使用非AVX指令修改xmm整数寄存器值
- 有4位,如何为AVX寄存器产生口罩
- 如何从AVX寄存器中获取数据
- SSE/AVX 寄存器的非零字节索引
- 是阻塞xmm/ymm寄存器的静态/静态本地SSE/AVX变量
- 用AVX寄存器联合类成员以减少内存访问
- 排列 AVX 寄存器的内容