Menggunakan GCC 6.3, kode C++ berikut:
#include <cmath>
#include <iostream>
void norm(double r, double i)
{
double n = std::sqrt(r * r + i * i);
std::cout << "norm = " << n;
}
menghasilkan berikut x86-64 majelis:
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)
Untuk panggilan ke std::sqrt
, GCC pertama tidak menggunakan sqrtsd
dan menyimpan hasilnya di stack. Jika itu meluap, maka panggilan libc sqrt
fungsi. Tapi itu tidak pernah menyimpan xmm0
setelah itu dan sebelum panggilan kedua untuk operator<<
, ini mengembalikan nilai dari stack (karena xmm0
hilang dengan panggilan pertama untuk operator<<
).
Dengan sederhana std::cout << n;
, it's bahkan lebih jelas:
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)
Mengapa GCC tidak menggunakan xmm0
nilai dihitung dengan libc sqrt
?
Itu doesn't perlu untuk memanggil sqrt
untuk menghitung hasil; it's telah dihitung oleh SQRTSD instruksi. Itu panggilan sqrt
untuk menghasilkan diperlukan perilaku yang sesuai dengan standar bila angka negatif dilewatkan untuk sqrt
(misalnya, errno
dan/atau meningkatkan floating-point pengecualian). Yang PXOR, UCOMISD, dan JBE petunjuk menguji apakah argumen kurang dari 0 dan melewatkan panggilan untuk sqrt
jika ini isn't benar.