我想尽可能地优化我的功能,我做的一件事是使用r8作为指针,因为这是指针在x64函数中被压入的寄存器。
但是在循环中稍后推动RSI或RDI,将指针移动到它们并使用它们会更快吗?
例如, mov [RSI],DL;将符合2个字节 和: mov [r8],DL;最多3个字节
因此,如果我执行100到200次循环,由于要解码的额外字节,r8会变慢吗?还是按下RSI并移动指针消除了任何可能的速度增加?显然,推和移动将在循环之外发生。
答案 0 :(得分:5)
取决于CPU。通常,平均指令大小为4就可以避免前端瓶颈,即使在像Core2这样的旧CPU上也是如此。
Sandybridge系列和Ryzen等现代CPU缓存解码的uops,并且对循环内的代码大小(或对齐方式)不那么敏感,仅在L1i和uop-cache占用空间较大时如此。
Nehalem具有一个“循环缓冲区”,用于最多28微秒的小循环。 (SnB系列也有此功能,但Skylake / Kaby Lake除外,后者已通过微代码更新禁用了该功能,因此它们甚至可以从uop缓存中运行很小的循环)。 Core2具有最多64个字节的预解码循环缓冲区。 (请参阅Agner Fog的指南)。
但是,是的,通常,较高的代码密度更好,因此,最好使用非REX寄存器来存储指针和32位值,对始终需要REX.W的64位整数使用r8-r15 强>。但是通常不值得花费额外的指令来实现这一目标。 uop计数通常比代码大小要大得多,尤其是在循环内。
带有性能计数器的配置文件,以查找循环中是否存在任何前端瓶颈。如果是这样,请确保保存/恢复更多的低调,例如RBP,并在函数内部使用它们代替R8。 (但是请记住,[rbp]
实际上需要disp8 = 0,[rbp+0]
。)
进一步阅读:
x86在Stack Overflow上的性能解答(其中许多是我的,但其他一些已经发布了一些很棒的东西)
还有一些与循环无关的更普通的东西:
DL
。