【发布时间】:2017-05-10 13:14:58
【问题描述】:
Appel 在第 8 页的“Runtime Tags Aren't Necessary”中解释了如何通过标记指针来区分整数和指针:
一些实现使用低位标记 0 表示整数,然后是整数 然后可以用普通的机器加法指令进行加法,没有 移动或校正将是必要的(因为 2x + 2y = 2(x + y))。这要求指针的标记为 1;但是指针获取可以用奇数偏移量来补偿。
想法是:如果指针对齐,则值是 2 或 4 的倍数。在这种情况下,低 1 或 2 位始终为零,可以设置为某个值以实现标记以区分整数来自指针。
英特尔语法中没有偏移的无标记指针获取是:
mov eax, DWORD PTR [ebx]
而带偏移量的等效标记指针获取是这样的:
mov eax, DWORD PTR [ebx-0x1]
两次提取的周期有何不同?
【问题讨论】:
-
fetch 通常意味着获取下一批指令,并且此级别的理智处理器将对齐并以总线大小的块的倍数执行此操作。未对齐的访问最多会导致开销之上的额外时钟,因为您必须执行额外的数据周期才能获得该额外项目(最好有时数据可以移动取决于总线架构)。但也可能将您推入一个完全独立的总线循环,具体取决于总线。说它是 32 位宽(与处理器是 32 位还是 64 位无关)并且您执行对齐的 64 位操作...
-
现代处理器是超标量,因此您无法真正计算周期。查看 Agner Fog 的表格了解性能详情。通常,一个 SIB 字节有轻微的性能损失,这取决于很多外部因素。
-
我无法测量任何差异(在 Haswell 上),但两者的延迟都是 5,而且通常报告它更低,因此这可能是测量错误。无论哪种方式,Agner 的表通常都表示加载和存储的“所有寻址模式”。
-
我不理解这个问题的批评者。它的姿势非常好,清晰且独立。我也相信哈罗德回答了它;通过添加关于偏移加载/存储的额外字节的注释以及在使用指针时这种加载/存储非常频繁的事实,可以获得完整的答案。
-
两条指令“执行”内存提取的时间相同,因为执行完全相同的内存提取操作。现在是获取指令、解码指令并计算要获取的可能不同的地址的时候了。 BeeOnRope 的回答表明,最后一个或两个因素可以在延迟上产生 1 个周期的差异,但在这种情况下通常不会。然而,代码大小的增加,不仅仅是一个字节,而是每个指针访问一个字节,这样会损害性能,因为它会更快地将代码推出 L1 缓存。