繁体   English   中英

x86 SIMD 指令 16 字节 alignment 汇编(没有 C 内在函数)

[英]x86 SIMD instructions 16 byte alignment in assembly (Without C intrinsics)

假设我有一个长度未知8 字节元素数组,从 memory 传递到我的程序集 function。 我想对其进行一些128 位SIMD 操作(最高 SSE4)。 memory 最好是 16 字节对齐的。 所以我会检查数组是否对齐,然后根据使用movapsmovups

我知道您可以通过以下方式检查 16 字节 alignment:

test dil, 0xf        ; rdi stores address of array

如果它不是 16 字节对齐的,那么检查它是否是 8 字节对齐是好的还是有用的,这意味着它是 8 的奇数倍?

test dil, 0x7           ; ZF=1 here after rdi&0xf !=0 implies rdi%16 == 8

如果这是真的,那么我应该对数组的第一个元素做一个额外的步骤,然后再movaps加载数组元素吗? 否则我应该只使用像movups这样的未对齐操作吗?

它像这样工作吗?

如果您的 arrays通常由 16 对齐,则最好不要进行更多检查以查找奇数开始的情况,只需使用未对齐的版本,除非由于某种原因它更糟。

但是,如果它们通常按 8 对齐(但不知道它们是否按 16 对齐),那么您可能只需检查 alignment 8 并无分支地处理对齐情况下可能未对齐的第一次迭代,见下文 (否则就退回到您完全未对齐的情况。)

如果重叠不是问题(例如 c[] = a[]+b[],或类似 memset 的存储或其他),一个好的技术是始终使用未对齐的加载/存储执行第一个向量,然后前进到第一个对齐的向量( add rdi, 16 / and rdi, -16 )。 如果输入是对齐的,则不会重叠。 否则,它会部分重叠,并且存储缓冲区 + L1d 缓存会有效地处理它。

这使得对齐案例的成本最小,并避免了分支错误预测的机会。

将指针向上/向下舍入到 alignment 边界很便宜,只是一个and ,但你确实有剥离整个循环体副本的代码大小成本。 因此,就启动开销而言,它并不是完全免费的,但至少这种启动开销可以与数据中的缓存未命中重叠。


但请注意,许多 SIMD 函数具有多个指针输入,这些指针输入可能相互错位。 在这种情况下,标准建议是对齐 output 并继续使用movups作为输入。 虽然如果前端是瓶颈,您可能会选择达到输入的 alignment 边界,以便您可以将 memory 源操作数折叠成 ALU 指令,如xorps xmm0, [rdi]并使用movups存储。

但是,如果前端以外的任何东西(例如缓存或 memory 吞吐量)是瓶颈,那么您通常需要对齐目标。 英特尔的优化手册对此有一些建议。 部分原因是负载吞吐量通常是存储吞吐量的 2 倍(直到 IceLake),因此负载硬件更容易吸收拆分负载的额外工作。 此外,使用较少的存储存储完整的缓存行可以帮助减少行被驱逐(写回)但随后您再次存储到它并且它必须被获取+弄脏并最终再次写回的情况,而不仅仅是获取。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM