Tek duyarlıklı yüzdelerini bellekten okuması gereken bazı kodları en iyi duruma getirmeye çalışıyorum ve onlarda aritmetiği iki kat hassasiyetle gerçekleştiriyorum. Bu, bellekte verileri tek bir hassasiyet olarak saklayan kod, verileri bellekte çift duyarlık olarak depolayan eşdeğer koddan önemli ölçüde yavaş olduğu için önemli bir performans darboğazı haline geliyor.GCC ve Clang neden cvtss2sd [memory] kullanıyor?
#include <cstdio>
// noinline to force main() to actually read the value from memory.
__attributes__ ((noinline)) float* GetFloat() {
float* f = new float;
*f = 3.14;
return f;
}
int main() {
float* f = GetFloat();
double d = *f;
printf("%f\n", d); // Use the value so it isn't optimized out of existence.
}
Hem GCC ve clang cvtss2sd
talimat kaynak argüman olarak bellek desteklediği halde iki ayrı talimatlar olarak çift duyarlılığa *f
yüklenmesini ve dönüştürme işlemi: Aşağıda benim konunun özünü yakalayan bir oyuncak C++ programıdır . Agner Fog, cvtss2sd r, m
, çoğu mimaride movss r, m
kadar hızlı yürütür ve sonradan cvtss2sd r, r
sonradan yürütme gereksinimi vardır. Bununla birlikte, Clang main()
için aşağıdaki kodu oluşturur:
main PROC
push rbp ;
mov rbp, rsp ;
call _Z8GetFloatv ;
movss xmm0, dword ptr [rax] ;
cvtss2sd xmm0, xmm0 ;
mov edi, offset ?_001 ;
mov al, 1 ;
call printf ;
xor eax, eax ;
pop rbp ;
ret ;
main ENDP
GCC benzer verimsiz kodu oluşturur. Neden bu derleyicilerden hiçbiri cvtss2sd xmm0, dword ptr [rax]
gibi bir şey üretmiyor?
EDIT: Harika yanıt, Stephen Canon! Gerçek kullanım durumum için Clang'ın assembly dili çıktısını aldım, onu bir satır içi ASM olarak bir kaynak dosyaya yapıştırdım, karşılaştırdım, sonra burada tartışılan değişiklikleri yaptım ve tekrar karşılaştırdım. cvtss2sd [memory]
'un aslında daha yavaş olduğuna inanamadım.
İlginç, ancak iki soruya yol açar: 1. Neden yüksek bitler sıfırlanmıyor? Muhtemelen bu talimatı kullanıyorsanız, amacınız vektörel olmayan kod yazmaktır. 2. GCC ve Clang, xmm kaydının yüksek bitleri kullanılmadığında bile, örneğin, daha sonra sadece vektörel olmayan talimatlar kullanıldığında bile bunu yapmakta gibi görünmektedir. Bu neden? – dsimcha
1. Intel bunu bu şekilde yapmayı seçti; neden çok önemli değil. Bazen yararlıdır, ama muhtemelen değerinden daha fazla belaya neden olur. 2. Kısmi kayıt güncelleme tehlikesi, XMM kayıtlarının yüksek kısmı hiç kullanılmamış olsa bile mevcuttur. Onu bu kadar sinsice yapan şey budur. –
Düzenlemenizdeki daha ayrıntılı açıklama müthiş! Tek sorum şu ki, neden CPU'nun mantıksal mantığı üst quadword bağımlılıkları bağımsız olarak düşük quadword bağımlılıklarını takip etmiyor ve xxxsd komutlarının sadece registerın düşük quadword'undan okuduğunu/yazdığını anlıyor musunuz? – dsimcha