为什么编译器会在编译的汇编代码中生成额外的sqrts

Sto*_*one 14 c assembly gcc x86-64 compiler-optimization

我正在尝试使用以下简单的C代码来分析计算sqrt所需的时间,其中readTSC()是一个读取CPU循环计数器的函数.

double sum = 0.0;
int i;
tm = readTSC();
for ( i = 0; i < n; i++ )
   sum += sqrt((double) i);
tm = readTSC() - tm;
printf("%lld clocks in total\n",tm);
printf("%15.6e\n",sum);
Run Code Online (Sandbox Code Playgroud)

但是,当我使用打印出汇编代码时

gcc -S timing.c -o timing.s
Run Code Online (Sandbox Code Playgroud)

在英特尔机器上,结果(如下所示)令人惊讶?

为什么汇编代码中有两个sqrts,一个使用sqrtsd指令而另一个使用函数调用?它是否与循环展开和尝试在一次迭代中执行两个sqrts相关?

以及如何理解这条线

ucomisd %xmm0, %xmm0
Run Code Online (Sandbox Code Playgroud)

为什么它与%xmm0自身相比?

//----------------start of for loop----------------
call    readTSC
movq    %rax, -32(%rbp)
movl    $0, -4(%rbp)
jmp .L4
.L6:
cvtsi2sd    -4(%rbp), %xmm1
// 1. use sqrtsd instruction
sqrtsd  %xmm1, %xmm0
ucomisd %xmm0, %xmm0
jp  .L8
je  .L5
.L8:
movapd  %xmm1, %xmm0
// 2. use C funciton call
call    sqrt
.L5:
movsd   -16(%rbp), %xmm1
addsd   %xmm1, %xmm0
movsd   %xmm0, -16(%rbp)
addl    $1, -4(%rbp)
.L4:
movl    -4(%rbp), %eax
cmpl    -36(%rbp), %eax
jl  .L6
//----------------end of for loop----------------
call    readTSC
Run Code Online (Sandbox Code Playgroud)

Jes*_*ter 23

它使用库sqrt函数进行错误处理.请参阅glibc的文档:20.5.4按数学函数报告错误:数学函数设置errno为与没有IEEE754异常标志的系统兼容.相关:glibc的math_error(7)手册页.

作为优化,它首先尝试通过内联sqrtsd指令执行平方根,然后使用ucomisd设置标志的指令检查结果,如下所示:

CASE (RESULT) OF
   UNORDERED:    ZF,PF,CF  111;
   GREATER_THAN: ZF,PF,CF  000;
   LESS_THAN:    ZF,PF,CF  001;
   EQUAL:        ZF,PF,CF  100;
ESAC;
Run Code Online (Sandbox Code Playgroud)

特别是,比较a QNaN和它本身将返回UNORDERED,如果你试图取负数的平方根,你会得到.这由jp分支机构负责.该je检查只是妄想,检查精确的相等.


另请注意,gcc有一个-fno-math-errno选项会牺牲此错误处理速度.此选项是其中一部分-ffast-math,但可以单独使用,而不启用任何更改结果的优化.

sqrtsd单独为负和NaN输入正确生成NaN,并设置IEEE754无效标志.检查和分支只是为了保留errno大多数代码不依赖的设置语义.

-fno-math-errno是Darwin(OS X)的默认值,数学库从不设置errno,因此可以在不进行此检查的情况下内联函数.

  • @harold:`-fno-math-errno`消除了测试,更安全. (7认同)
  • 请注意,`-ffast-math'不仅仅是为了速度而牺牲错误处理.特别是,它还违反了IEEE 754合规性,即谨慎使用,并且只有在您知道自己在做什么的情况下才能使用.另见http://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do (2认同)
  • 是的,这是对的,我只是觉得每次提及快速数学标志都应带有警告标签,这就是我添加评论的原因. (2认同)