Yur*_*riy 3 assembly simd cpu-architecture avx micro-optimization
在 avx 指令中用作源的寄存器何时可以在指令开始处理后重用?
例如:我想使用vgatherdps消耗两个 ymm 寄存器的指令,其中之一是位移索引。我意识到vgatherdps收集数据需要花费大量时间,因为数据的局部性较差。
位移索引寄存器是否会在指令执行期间被保留,或者我可以在后续指令中重用它而无需挂起管道?
所有带有 AVX 的 x86 CPU 都通过寄存器重命名进行乱序执行,以隐藏 Write-After-Write 和 Write-After-Read危险。看
为什么mulss在Haswell上只需要3个周期,与Agner的指令表不同?(用多个累加器展开 FP 循环)(关于危险和寄存器重命名的部分靠近我的答案顶部)
对 Intel Sandybridge 系列 CPU 中的管道进行去优化,这同样说明这不是问题。
每条汇编指令需要多少个CPU周期?- 依赖链对性能至关重要;寄存器重命名后,只有 RAW(写入后读取)真正的依赖关系很重要。
您永远不必担心由于读取或写入先前值的指令执行缓慢而导致对寄存器的只写访问停止。 (乱序执行有其局限性,物理寄存器文件条目的数量就是其中之一,但这是与 WAR / WAW 危险不同的一个因素。)
寄存器重命名的全部目的是使同一寄存器的新(独立)使用像使用不同的寄存器一样执行,从而允许CPU利用指令级并行性。
例如,vmovdqa ymm2, [rdi]不关心先前读取或写入 ymm2(或其 xmm2 低半部分)的指令;vmovdqa的目标始终是只写的。
既然你提到了聚集,vgatherdps它本身就不是只写其目的地;它根据掩码向量进行合并。因此,如果您在循环中重复收集到同一个寄存器(例如ymm0),您可能希望vpxor xmm0,xmm0,xmm0打破依赖性。
但你可能不需要;在 Intel CPU 上,即使读写目标寄存器尚未“准备好”作为输入,收集元素的实际加载也可以开始。 https://uops.info/ 测量了Skylake 上操作数 1 到操作数 1 在 1 个周期延迟下的延迟。(至少当掩码为全一时;这可能是非故障情况的特殊情况)。
因此vgatherdps ymm0, [rdi+ymm5*4], ymm1可以在就绪ymm0后的周期中写入(如果和以及指向的内存提前 22 个周期就绪)。(收集吞吐量比这更糟糕;他们通过使用像 10x 这样的指令链来测量吞吐量,正如您在该链接的实验 2 和 3 中看到的那样。)ymm0ymm5ymm1vshufpd ymm0, ymm0, ymm0, 0
然而,例如 Zen3 上的情况就不太好了。Zen 3上的 vgatherdps ymm从操作数 1 -> 1 of 8 个周期有延迟。但这仍然比从索引向量就绪 -> 目标向量就绪的 28 个周期延迟要短得多。(2 -> 1)
(对于掩码向量设置为全一的正常收集,您可以使用vpcmpeqd ymm1, ymm1, ymm1。它被认为独立于先前的值,就像异或归零习惯用法一样,因此即使您使用的是看起来它实际上会读取和比较的指令。这意味着您已经破坏了涉及掩码向量的 dep 链。有趣的是,在 Skylake 上,如果您有意避免破坏依赖关系,从掩码输入到输出的周期延迟为 0。请参阅uops.info Skylake 延迟页面上的 3->1 部分。大概会收集类似于掩码的 vpxor-zeroing 的工作,只有在元素上存在页面错误(或其他错误)时才会采取不同的做法。)
| 归档时间: |
|
| 查看次数: |
503 次 |
| 最近记录: |