我有一个简单的程序
int main()
{
return 2*7;
}GCC和clang都打开优化开关,快速生成2指令二进制,但icc给出了奇怪的输出。
push rbp #2.1
mov rbp, rsp #2.1
and rsp, -128 #2.1
sub rsp, 128 #2.1
xor esi, esi #2.1
mov edi, 3 #2.1
call __intel_new_feature_proc_init #2.1
stmxcsr DWORD PTR [rsp] #2.1
mov eax, 14 #3.12
or DWORD PTR [rsp], 32832 #2.1
ldmxcsr DWORD PTR [rsp] #2.1
mov rsp, rbp #3.12
pop rbp #3.12
ret发布于 2018-09-03 00:56:42
我不知道ICC为什么选择用2行缓存对齐堆栈:
and rsp, -128 #2.1
sub rsp, 128 #2.1这很有趣。L2缓存有一个邻接行预取器,它喜欢将行对(在128个字节对齐组中)拉到L2中。但main的堆栈框架通常不被大量使用。也许重要的变量在一些程序中被分配到那里。(这也解释了如何设置rbp,以保存旧的RSP,以便在ANDing之后返回。gcc用RBP在对齐堆栈的功能上制作堆栈帧。)
其余的是因为main() -ffast-math 是特殊的,而ICC默认支持-ffast-math。(这是英特尔的“肮脏”小秘密之一,让它能够自动矢量化更多的浮点代码。)
这包括在main顶部添加代码,以在MXCSR (SSE状态/控制寄存器)中设置DAZ / FTZ位。有关这些部分的更多信息,请参阅英特尔的x86手册,但它们实际上并不复杂:
( main()**,ISO C++禁止程序重新调用,这样编译器就可以将运行一次的内容放入** main 本身,而不是在CRT启动文件中)。gcc/clang使用-ffast-math指定用于链接设置MXCSR的CRT启动文件中的链接。但是,在使用gcc/clang编译时,它只影响允许优化的代码-gen。即把FP加/mul当作联想,当不同的时间意味着它真的不是。这与设置DAZ/FTZ完全无关。
在这里,Denormal被用作次法线的同义词:一个指数最小的FP值和一个有意义的值,其中隐式前导位为0,而不是1。即小于DBL_MIN的值,最小可表示的规范化浮点/双值。
数。
产生低于正常的结果的指令可能要慢得多:为了优化延迟,某些硬件中的快速路径假设标准化结果,如果结果不能规范化,则需要微码辅助。使用perf stat -e fp_assist.any对此类事件进行计数。
来自Bruce的精彩系列FP文章: 这是不正常的--奇装车的性能。另外:
Agner已经做了一些测试(见他的微弓pdf),并为Haswell/Broadwell做了报告:
底流与 当浮点操作接近底流时,就会出现低于正常值的数字。在某些情况下,处理低于正常值的数字非常昂贵,因为低于正常的结果是由微代码异常处理的。 Haswell和Broadwell在所有情况下都有大约124个时钟周期的惩罚,在所有情况下,对正常数的运算都会给出低于正常的结果。对于法线数和次法线数之间的乘法,无论结果是正常的还是次正常的,都有类似的惩罚。无论结果如何,都不会对添加一个正常数和一个低于正常值的数字进行惩罚。对于溢出、下溢、无穷大或非a数的结果,没有任何惩罚. 如果MXCSR寄存器中设置了“刷新到零”模式和“取消-零”模式,则避免了对低于正常数的惩罚。
所以在某些情况下,现代英特尔CPU即使在异常情况下也能避免处罚,但是
https://stackoverflow.com/questions/52141947
复制相似问题