Я экспериментирую с созданной сборкой и нашел интересную вещь. Есть две функции, выполняющие одинаковые вычисления. Единственное различие между ними - это способ суммирования результатов.
#include <cmath>
double func1(double x, double y)
{
double result1;
double result2;
if (x*x < 0.0) result1 = 0.0;
else
{
result1 = x*x+x+y;
}
if (y*y < 0.0) result2 = 0.0;
else
{
result2 = y*y+y+x;
}
return (result1 + result2) * 40.0;
}
double func2(double x, double y)
{
double result = 0.0;
if (x*x >= 0.0)
{
result += x*x+x+y;
}
if (y*y >= 0.0)
{
result += y*y+y+x;
}
return result * 40.0;
}
Сборка, сгенерированная с помощью x86 clang 3.7 с -O2
на gcc.godbolt.org, пока еще очень отличается и неожиданна. (компиляция на gcc приводит к аналогичной сборке)
.LCPI0_0:
.quad 4630826316843712512 # double 40
func1(double, double): # @func1(double, double)
movapd %xmm0, %xmm2
mulsd %xmm2, %xmm2
addsd %xmm0, %xmm2
addsd %xmm1, %xmm2
movapd %xmm1, %xmm3
mulsd %xmm3, %xmm3
addsd %xmm1, %xmm3
addsd %xmm0, %xmm3
addsd %xmm3, %xmm2
mulsd .LCPI0_0(%rip), %xmm2
movapd %xmm2, %xmm0
retq
.LCPI1_0:
.quad 4630826316843712512 # double 40
func2(double, double): # @func2(double, double)
movapd %xmm0, %xmm2
movapd %xmm2, %xmm4
mulsd %xmm4, %xmm4
xorps %xmm3, %xmm3
ucomisd %xmm3, %xmm4
xorpd %xmm0, %xmm0
jb .LBB1_2
addsd %xmm2, %xmm4
addsd %xmm1, %xmm4
xorpd %xmm0, %xmm0
addsd %xmm4, %xmm0
.LBB1_2:
movapd %xmm1, %xmm4
mulsd %xmm4, %xmm4
ucomisd %xmm3, %xmm4
jb .LBB1_4
addsd %xmm1, %xmm4
addsd %xmm2, %xmm4
addsd %xmm4, %xmm0
.LBB1_4:
mulsd .LCPI1_0(%rip), %xmm0
retq
func1
компилируется в ветвящуюся сборку с гораздо меньшими инструкциями, чем func2
. таким образом, func2
ожидается намного медленнее, чем func1
.
Может ли кто-нибудь объяснить это поведение?