首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么icc要为一个简单的主设备生成奇怪的程序集?

为什么icc要为一个简单的主设备生成奇怪的程序集?
EN

Stack Overflow用户
提问于 2018-09-03 00:22:12
回答 1查看 319关注 0票数 3

我有一个简单的程序

代码语言:javascript
复制
int main()
{
    return 2*7;
}

GCC和clang都打开优化开关,快速生成2指令二进制,但icc给出了奇怪的输出。

代码语言:javascript
复制
     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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-03 00:56:42

我不知道ICC为什么选择用2行缓存对齐堆栈:

代码语言:javascript
复制
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手册,但它们实际上并不复杂:

  • DAZ: Denormals为零:作为SSE/AVX指令的输入,取消正态被视为零。
  • FTZ:刷新为零:当舍入SSE/AVX指令的结果时,低于正常的结果被刷新为零。

相关:SSE "denormals是零“选项

( 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即使在异常情况下也能避免处罚,但是

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52141947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档