Gebruik GCC 6.3, de volgende C++-code:
#include <cmath>
#include <iostream>
void norm(double r, double i)
{
double n = std::sqrt(r * r + i * i);
std::cout << "norm = " << n;
}
genereert de volgende x86-64-assembly:
norm(double, double):
mulsd %xmm1, %xmm1
subq $24, %rsp
mulsd %xmm0, %xmm0
addsd %xmm1, %xmm0
pxor %xmm1, %xmm1
ucomisd %xmm0, %xmm1
sqrtsd %xmm0, %xmm2
movsd %xmm2, 8(%rsp)
jbe .L2
call sqrt
.L2:
movl std::cout, %edi
movl $7, %edx
movl $.LC1, %esi
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
movsd 8(%rsp), %xmm0
movl std::cout, %edi
addq $24, %rsp
jmp std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
Voor de aanroep naar std::sqrt
doet GCC dit eerst met behulp van sqrtsd
en slaat het resultaat op de stapel op. Als het overloopt, roept het de functie libc sqrt
aan. Maar daarna slaat het nooit de xmm0
op en vóór de tweede aanroep van operator<<
herstelt het de waarde van de stapel (omdat xmm0
ging verloren bij de eerste oproep naar operator<<
).
Met een eenvoudigere std::cout << n;
, het is nog duidelijker:
subq $24, %rsp
movsd %xmm1, 8(%rsp)
call sqrt
movsd 8(%rsp), %xmm1
movl std::cout, %edi
addq $24, %rsp
movapd %xmm1, %xmm0
jmp std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
Waarom gebruikt GCC de xmm0
-waarde niet berekend door libc sqrt
?
Antwoord 1, autoriteit 100%
Het is niet nodig om sqrt
aan te roepen om het resultaat te berekenen; het is al berekend door de SQRTSD-instructie. Het roept sqrt
aan om het vereiste gedrag volgens de standaard te genereren wanneer een negatief getal wordt doorgegeven aan sqrt
(stel bijvoorbeeld errno
in en/of een drijvende-komma-uitzondering opwerpen). De PXOR-, UCOMISD- en JBE-instructies testen of het argument kleiner is dan 0 en sla de aanroep over naar sqrt
als dit niet waar is.