rus*_*tyx 5 performance assembly x86-64 intel multiplication
在/O2(发布)模式下查看由Visual Studio(2015U2)生成的程序集时,我看到这个"手动优化"的C代码被转换回乘法:
int64_t calc(int64_t a) {
return (a << 6) + (a << 16) - a;
}
Run Code Online (Sandbox Code Playgroud)
部件:
imul rdx,qword ptr [a],1003Fh
Run Code Online (Sandbox Code Playgroud)
所以我想知道这是否真的比按照它的编写方式更快,类似于:
mov rbx,qword ptr [a]
mov rax,rbx
shl rax,6
mov rcx,rbx
shl rcx,10h
add rax,rcx
sub rax,rbx
Run Code Online (Sandbox Code Playgroud)
我总是觉得乘法总是比几个班次/加法慢?现代英特尔x86_64处理器不再是这种情况吗?
Pet*_*des 11
没错,现代的x86 CPU(尤其是Intel)具有非常高的性能乘数.
imul r, r/m并且imul r, r/m, imm是3周期延迟,Intel SnB系列和AMD Ryzen每1c吞吐量一个,即使是64位操作数大小.
在AMD Bulldozer系列中,它具有4c或6c延迟,每2c一个或每4c吞吐一个.(64位操作数大小的较慢时间).
来自Agner Fog指令表的数据.另请参阅x86标记wiki 中的其他内容.
现代CPU中的晶体管预算非常庞大,并且允许以这种低延迟进行64位乘法所需的硬件并行度.(制作大型快速乘法器需要很多加法器).
受功率预算限制,而不是晶体管预算,意味着可以使用专用硬件来实现许多不同功能,只要它们不能同时切换(https://en.wikipedia.org/wiki/Dark_silicon)).例如,你不能在Intel CPU上同时使pext/ pdepunit,整数乘法器和向量FMA单元饱和,因为它们中的许多都位于相同的执行端口上.
有趣的事实:imul r64也是3c,所以你可以在3个周期内获得完整的64*64 => 128b乘法结果. imul r32但是,4c延迟和额外的uop.我的猜测是额外的uop/cycle将64位结果从常规64位乘法器分成两个32位半.
编译器通常会针对延迟进行优化,并且通常不知道如何优化短的独立依赖链以实现吞吐量,而不是长循环传输的依赖链,这是延迟的瓶颈.
gcc和clang3.8及以后使用最多两个LEA指令而不是imul r, r/m, imm.我认为imul如果替代方案是3个或更多指令(不包括mov),gcc将使用.
这是一个合理的调整选择,因为3指令dep链的长度与imulIntel上的相同.使用两个1周期指令花费额外的uop来将延迟缩短1个周期.
imul除了仅需要单个LEA或移位的乘数外,clang3.7和更早版本倾向于偏向.所以clang最近改为优化延迟而不是通过小常数乘以吞吐量.(或者可能出于其他原因,比如不与其他与竞争对手相同的其他东西竞争.)
int foo (int a) { return a * 63; }
# gcc 6.1 -O3 -march=haswell (and clang actually does the same here)
mov eax, edi # tmp91, a
sal eax, 6 # tmp91,
sub eax, edi # tmp92, a
ret
Run Code Online (Sandbox Code Playgroud)
clang3.8及更高版本生成相同的代码.
| 归档时间: |
|
| 查看次数: |
1116 次 |
| 最近记录: |