Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么icc为一个简单的main生成奇怪的程序集?_C++_Assembly_X86_Code Generation_Icc - Fatal编程技术网

C++ 为什么icc为一个简单的main生成奇怪的程序集?

C++ 为什么icc为一个简单的main生成奇怪的程序集?,c++,assembly,x86,code-generation,icc,C++,Assembly,X86,Code Generation,Icc,我有一个简单的建议: 启用优化的GCC和clang都可能生成2个指令二进制,但icc给出了奇怪的输出 push rbp #2.1 mov rbp, rsp #2.1 and rsp, -128 #2.1

我有一个简单的建议:

启用优化的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

我不知道为什么ICC选择将堆栈按2条缓存线对齐:

and       rsp, -128                                     #2.1
sub       rsp, 128                                      #2.1
那很有趣。二级缓存有一个相邻行预取器,它喜欢将成对的行(在128字节对齐的组中)拉入二级缓存。但main的堆栈框架通常不会被大量使用。可能在某些程序中分配了重要的变量。(这也解释了如何设置
rbp
,以保存旧的RSP,以便它可以在安定后返回。gcc在函数中使用rbp生成堆栈帧,并在函数中对齐该堆栈。)


其余的原因是
main()
是特殊的,ICC默认启用
-ffast math
。(这是英特尔“肮脏”的小秘密之一,它可以自动矢量化更多的浮点代码。)

这包括在
main
顶部添加代码,以设置MXCSR(SSE状态/控制寄存器)中的DAZ/FTZ位。有关这些位的更多信息,请参阅英特尔x86手册,但它们并不复杂:

  • DAZ:非规范值为零:作为SSE/AVX指令的输入,非规范值被视为零

  • FTZ:刷新到零:当舍入SSE/AVX指令的结果时,低于正常值的结果刷新到零

相关的:

(<强> ISO C++禁止程序调用回<代码>主(),因此编译器可以在

main
本身而不是在CRT启动文件中放置run-one-one-one-one-one-one-run-one-one-one-one-one-one-one-one-one-one-one-one-run-one-one-one-one-one-one-one-one-one-run-one-one-one-one-one-one-run-one-one-one-one-one-one-one-one-one-run-one-one-one-one-one-one-one-one-one-将FP add/mul设置为关联,而不同的时间表示它实际上不是。这与设置DAZ/FTZ完全无关)


非规范在这里被用作次规范的同义词:具有最小指数和有效位的FP值,其中隐式前导位为0而不是1。i、 e.幅值小于最小可表示的标准化浮点/双精度的值


产生次正常结果的指令可能会慢得多:为了优化延迟,某些硬件中的快速路径假设标准化结果,如果结果无法标准化,则需要微码辅助。使用
perf stat-e fp_assist.any
统计此类事件

来自Bruce Dawson的优秀FP系列文章:。此外:

Agner Fog进行了一些测试(见his),并为Haswell/Broadwell提供了报告:

下溢和低于正常值

当浮点运算接近极限时,会出现低于正常值的数字 下溢。在某些情况下,处理低于正常值的数字非常昂贵 因为低于正常值的结果是由微码处理的 例外情况

哈斯韦尔和布罗德韦尔的罚球时间约为124小时 所有情况下的循环,其中对正常数的操作给出 低于正常的结果。乘法也有类似的惩罚 介于正常数和次正常数之间,无论 结果正常或低于正常。添加一个正常值不会受到处罚 和一个低于正常值的数字,不管结果如何。没有处罚 对于溢出、下溢、无穷大或非数字结果

如果“齐平为零”,则可避免对低于正常值的数字进行处罚 模式和“非规范为零”模式均在MXCSR中设置 登记


因此,在某些情况下,现代Intel CPU即使在低于正常值的情况下也可以避免处罚,但是

如果您将函数名更改为
main2
(或任何其他名称),代码将发生更改-这已成为常态。这意味着,
main
是icc编译器的特殊名称,它会在此处生成额外的特殊代码icc可能会为
main
生成模板代码,作为托管环境的一部分,不会得到优化。将
main
重命名为其他名称或尝试使用
-ffreestanding
main
获得特殊待遇。谢谢。如果你们中的任何一个想把你的评论放到A中,并解释为什么ICC对待不同的主题,我会接受A@ OrnSeHiSalOM:问题是关于C++程序。GOOBBIT链接显示,该源被编译为C++,而不是C.ICC将作为C程序发出相同的ASM(例如PASS <代码> -XC<代码>),但是任意地将标签更改为C是不合适的。我的回答已经提到了C++程序的规则:程序调用>代码>主代码>代码>。(ISO C有相同的规则,但您没有编辑我的答案以匹配您对问题的更改。)@OrenIsh:不过,您其余的编辑都很好。您能解释一下为什么您说主堆栈框架没有被大量使用。。。我假设从main调用的所有函数(不包括异步调用和启动新线程)都使用“main stack”,因此如果它们在128B对齐,但main不对齐,它们将不会对齐,因为stack frames stacks:)@nosenseal:是的,它们都使用主调用堆栈(除非启动新线程),但其他函数调用仅保持16字节对齐。我还没有详细研究ICC的
main
在进行
调用时是否实际对齐了RSP 128字节,或者它是否只是对齐了128字节,然后正常工作,保留了16字节的倍数。
and       rsp, -128                                     #2.1
sub       rsp, 128                                      #2.1