_mm256_lddqu_si256和_mm256_loadu_si256之间有什么区别

Jim*_*mbo 6 x86 simd intrinsics avx micro-optimization

_mm256_lddqu_si256基于我在网上找到的一个例子,我一直在使用.后来我发现了_mm256_loadu_si256.英特尔内在函数指南仅指出lddqu版本在跨越缓存行边界时可能表现更好.可能有什么好处loadu?一般来说,这些功能有何不同?

Pet*_*des 6

没有理由使用_mm256_lddqu_si256它,认为它是一个同义词_mm256_loadu_si256. lddqu仅存在于历史原因,因为x86演变为具有更好的未对齐向量加载支持,并且支持AVX版本的CPU以相同方式运行它们.没有AVX512版本.

编译器仍然尊重lddqu内在函数并发出该指令,因此如果您希望代码以相同的方式运行但具有不同的校验和或机器代码字节,则可以使用它.


没有x86微体系结构与之vlddqu不同vmovdqu.即两个操作码可能在所有AVX CPU上解码为相同的内部uop.他们可能总是这样,除非一些非常低功耗或专门的微体系结构没有有效的未对齐向量载荷(这是Nehalem以来的事情).编译器vlddqu在自动矢量化时从不使用.

lddqumovdquPentium 4 不同.请参阅......一个CPU指令的历史:第1部分.LDDQU/movdqu解释.

lddqu允许(并且在P4 上确实)两个对齐的16B加载并获取该数据的窗口. movdqu在架构上只从预期的16个字节加载. 这对存储转发有影响:如果您正在加载仅使用未对齐存储存储的数据,请使用,movdqu因为存储转发仅适用于完全包含在先前存储中的负载.但是否则你一般都想使用lddqu.(这就是为什么他们不只是movdqu总是使用"好方法",而是为程序员引入了一条令人担心的新指令.但幸运的是,他们改变了设计,所以我们不必担心哪些不对齐加载指令再使用.)

它还对UnCacheable(UC)或Uncacheable Speculate Write-combined(UCSW,aka WC)内存类型(可能在它们后面有MMIO寄存器)的可观察行为的正确性产生影响.


两个asm指令中没有代码大小差异:

  # SSE packed-single instructions are shorter than SSE2 integer / packed-double
  4000e3:       0f 10 07                movups xmm0, [rdi]   

  4000e6:       f2 0f f0 07             lddqu  xmm0, [rdi]
  4000ea:       f3 0f 6f 07             movdqu xmm0, [rdi]

  4000ee:       c5 fb f0 07             vlddqu xmm0, [rdi]
  4000f2:       c5 fa 6f 07             vmovdqu xmm0, [rdi]
  # AVX-256 is the same as AVX-128, but with one more bit set in the VEX prefix
Run Code Online (Sandbox Code Playgroud)

在Core2及更高版本中,没有理由使用lddqu,但也没有任何缺点movdqu.英特尔放弃了lddquCore2 的特殊功能,因此两种选择都同样糟糕.

特别是在Core2上,避免在具有两个对齐加载和SSSE3的软件中进行缓存行拆分palignr有时是胜利movdqu,特别是在第二代Core2(Penryn)palignr上,Merom/Conroe只有一个shuffle uop而不是2.(Penryn将洗牌执行单元扩大到128b).

请参阅Dark Shikaris的2009年日记x264开发者博客文章:Cacheline拆分,更多关于未对齐负载策略的回顾,在过去的糟糕时期.

Core2之后的一代是Nehalem,它movdqu是一个单指令指令,在装载端口中具有专用硬件支持.它仍然是有用的,告诉编译器时指针对准(尤其是对于自动矢量化,尤其是没有AVX),但他们只是用它不是一个表现灾难movdqu无处不在,尤其是如果数据实际上在运行时对齐.


我不知道为什么英特尔甚至根本就制作了AVX版本lddqu.我想这是更简单的解码器只把该操作码为的别名movdqu/ vmovdqu在所有模式(与传统SSE前缀,或者AVX128/AVX256),而不是具有操作码解码与VEX前缀别的东西.

所有当前支持AVX的CPU都具有高效的硬件未对齐加载/存储支持,可以尽可能优化地处理它.例如,当数据在运行时对齐时,性能差异恰好为零vmovdqa.

这是不是的Nehalem之前的情况; movdqu并且lddqu用于解码到多个uop以处理可能未对齐的地址,而不是在加载端口中为此提供硬件支持,其中单个uop可以激活它而不是在未对齐的地址上发生错误.

但是,英特尔的ISA ref手册输入lddqu说256b版本最多可以加载64个字节(取决于实现):

如果源操作数跨越高速缓存行边界,则该指令可以改善相对于(V)MOVDQU的性能.在需要由(V)LDDQU加载的数据被修改并存储到相同位置的情况下,使用(V)MOVDQU或(V)MOVDQA代替(V)LDDQU.要将双四字移入或移出已知在16字节边界上对齐的存储单元,请使用(V)MOVDQA指令.

IDK有多少是故意写的,有多少只是(V)在更新AVX条目时预先添加的.我不认为英特尔的优化手册建议vlddqu在任何地方使用,但我没有检查.

没有AVX512版本vlddqu,所以我认为这意味着英特尔已经确定备用策略未对齐加载指令不再有用,甚至不值得保持其选项开放.