san*_*orn 0 c++ x86-64 inline-assembly intrinsics avx
这个想法是,我想收集的返回的值double成一个矢量寄存器,用于机加工imm width在一个时间而不第一存储回到存储器。
特定的处理vfma与其他两个操作数都是constexpr,因此它们可以简单地由_mm256_setr_pd调用或从 中对齐/未对齐的内存加载constexpr array。
有没有办法%ymm直接从 value in 中将double 存储在特定位置以%rax进行收集?
目标机器是 Kaby Lake。更有效的未来向量指令也是受欢迎的。
内联汇编通常是一个坏主意:现代编译器在 x86 内在函数方面做得很好。
将 a 的位模式double放入 RAX 通常也没有用,而且听起来你可能已经走错了路,进入了次优领域。Vector shuffle 指令通常更好:元素插入/提取指令已经在 Intel 硬件上花费了 shuffle uop,除了vmovq %xmm0, %rax获取低元素。
此外,如果您要将其插入到另一个向量中,则应该进行随机播放/立即混合。( vpermpd/ vblendpd).
L1d 和存储转发缓存速度很快,甚至存储转发停顿也不是灾难。在 ALU 与内存之间明智地选择,以将数据收集或分散到/从 SIMD 向量中。还要记住,插入/提取指令需要一个立即索引,所以如果你有一个向量的运行时索引,你肯定想要存储它和索引。(见https://agner.org/optimize/在和其他性能链接https://stackoverflow.com/tags/x86/info)
大量插入/提取可能会在 Haswell 及更高版本上的端口 5 上迅速出现瓶颈。 有关更多详细信息,请参阅从 GP regs 加载 xmm以及一些指向 gcc 错误报告的链接,其中我详细介绍了不同 uarch 上不同元素宽度的策略以及使用 SSE4.1 与不使用 SSE4.1 等的策略。
没有 PD 版本extractps r/m32, xmm, imm,并且insertps是 XMM 向量之间的随机播放。
要读/写 YMM 的低车道,您必须使用整数vpextrq $1, %xmm0, %rax/pinsrq $1, %rax, %xmm0。这些在 YMM 宽度中不可用,因此您需要多个指令来读/写高车道。
VEX 版本vpinsrq $1, %rax, %xmm0会将目标向量的完整 YMM 或 ZMM 宽度的高车道归零,这就是我建议pinsrq. 在 Skylake 及更高版本上,它不会导致 SSE/AVX 转换停顿。有关示例(NASM 语法),以及从 GP regs 加载 xmm,请参阅使用 ymm 寄存器作为“类似内存”的存储位置
对于低元素,用于vmovq %xmm0, %rax提取,它比vpextrq(1 uop 而不是 2)便宜。
对于 ZMM,我对来自 GP regs 问题的链接 XMM 的回答表明,您可以使用 AVX512F 将整数寄存器合并掩码到向量中,给定一个带有单个位集的掩码寄存器。
vpbroadcastq %rax, %zmm0{%k1}
Run Code Online (Sandbox Code Playgroud)
类似地,vpcompressq可以将单个位掩码选择的元素移动到底部 for vmovq。
但对于提取物,如果有一个索引,而不是1<<index与开始,你可能会更好过vmovd %ecx, %zmm1/vpermd %zmm0, %zmm1, %zmm2 / vmovq %zmm2, %rax。这个技巧甚至适用vpshufb于字节元素(至少有一个通道)。对于车道交叉,可能将 +vmovd与字节索引的高位混洗,然后使用索引的低位作为字内字节偏移量进行标量右移。另请参阅如何使用 _mm_extract_epi8 函数?用于可变索引仿真的内在函数pextrb。
我认为用 AVX2 在 YMM 的高车道上写一个元素的最佳选择需要一个临时寄存器:
vmovq %rax, %xmm0 (复制到划痕矢量)vinsertf128(AVX1) 或vpbroadcastq/洗牌到位vbroadcastsd。它比vpermq/vpermpd在 AMD上更快。(但 reg-reg 版本仍然是 AVX2-only)vblendpd(FP) 或vpblendd(integer) 到目标 YMM reg。与 dword 或更大元素宽度的立即混合非常便宜(英特尔上的任何矢量 ALU 端口为 1 uop)。这只有 3 个 uops,但其中 2 个需要 Intel CPU 上的端口 5。(因此它的成本与 a vpinsrq+ a blend相同)。只有混合在从向量输入到向量输出的关键路径上,设置ymm0fromrax是独立的。
要读取最高元素,vpermpd或vpermq $3, %ymm1, %ymm0(AVX2),然后vmovq从 xmm0。
要读取第二高的元素vextractf128 $1, %ymm1, %xmm0(AVX1) 和vmovq. vextractf128比vpermq/pdAMD CPU快。
个错误的选择,以避免划伤章第插入会vpermq或vperm2i128洗牌要更换成低车道四字,pinsrq(不 vpinsrq),然后vpermq将它放回正确的顺序。这都是随机 uop,并且pinsrq是 2 uop。(并导致 Haswell 上的 SSE/AVX 转换停顿,但不会导致 Skylake)。此外,所有这些操作都是您正在修改的寄存器的依赖链的一部分,这与在另一个寄存器中设置值和混合不同。
| 归档时间: |
|
| 查看次数: |
442 次 |
| 最近记录: |