Intel 上带偏移量和不带偏移量的内存获取之间的区别

Difference between memory fetch with and without offset on Intel

Appel 在第 8 页的“Runtime Tags Aren't Necessary”中解释了如何通过标记指针来区分整数和指针:

Some implementations use a low-order tag of 0 for integers, then integer addition can then be done with the ordinary machine add instruction, and no shifting or correction will be necessary (since 2x + 2y = 2(x + y)). This requires that pointers have a tag of 1; but pointer-fetches can be done with odd offsets to compensate.

想法是:如果指针对齐,则该值是 2 或 4 的倍数。在这种情况下,较低的 1 或 2 位始终为零,可以设置为某个值以实现标记区分整数和指针。

Intel 语法中没有偏移量的未标记指针提取是:

mov    eax, DWORD PTR [ebx]

带偏移量的等效标记指针提取是这样的:

mov    eax, DWORD PTR [ebx-0x1] 

两次抓取的周期有何不同?

寻址方式的复杂度一般对加载指令的吞吐量没有影响,但可能会对延迟有1个周期的影响1.

特别是简单寻址模式,即[base][base + offset],其中offset < 2048通常需要4个周期,而复杂模式(这是任何不简单的事情)需要 5 个周期。这是为了加载到通用寄存器:对于矢量加载,您通常会增加 1 或 2 个周期。

因此在您的情况下,您仅使用 base 且偏移量非常小,因此您应该获得 4 个周期的最快加载延迟。

这适用于 Intel,我不确定 AMD。

英特尔优化指南中有详细信息,但这里the source我能最快找到。

正如 Ross 在评论中提到的那样,使用偏移量至少还有一个小缺点:对于带有偏移量的版本,指令是 one byte longer(如果你的偏移量是 4 个字节长)超出 -128 到 127 的范围),这会稍微增加 icache 的压力。


1 不言而喻,这是针对L1中的命中率。如果你错过了 L1,延迟会更长 - 可能 很多 并且在这种情况下你是否仍然支付额外的周期可能并不重要(但我想你这样做,平均而言,因为在计算地址之前不会开始未命中。