Ich überlege gerade, wie ich eine Konstante (etwa 3.1415926535897931 oder ihre binäre Repräsentation 0x400921FB54442D18) möglichst schnell in eine Berechnung einbringe, und brauche eure Empfehlung für meine Alternativen:
- Standardmäßig speichert Visual C++ jede x64-Gleitkommakonstante im Datensegment und lädt sie vor ihrer Verwendung:
movsd xmm0,mmword ptr [__real@400921FB54442D18]
- Ist der Teil des Datensegments, in dem die Konstante liegt, außerhalb aller Caches, dauert die Bereitstellung rund 400 Takte. Wie viel von dieser Wartezeit kriegt die CPU in der Praxis versteckt?
- Intel warnt: MOVSD aktualisiert nur die niederwertigsten 64 Bits des Registers; das bedeutet, dass Register Renaming (und damit die Parallelisierung) erschwert werden.
- Integer-Konstanten können im Maschinentext hardcodet und über den Stapelspeicher geladen werden; beide sind quasi garantiert schon im Cache:
__declspec(align(16)) auto const binaryValue = 0x400921FB54442D18ull;
::_mm_cvtsd_f64(::_mm_load_sd((double const *)&binaryValue));
Resultat:
mov rbx,400921FB54442D18h
mov qword ptr [rsp+110h],rbx
movsd xmm0,mmword ptr [rsp+110h]
- Die letzten beiden mov(sd)s werden vor jeder weiteren Verwendung der Variable wiederholt; dass sich der Wert nicht ändert, verpasst Visual C++.
- Das movsd-Problem besteht weiter; aber so lange alles im Cache ist, sollte der Bedarf an Takten höchstens zweistellig sein.
- Der Stapelspeicher kann auch umgangen werden:
__declspec(align(16)) auto const binaryValue = 0x400921FB54442D18ull;
::_mm_cvtsd_f64(::_mm_set_sd((double const &)binaryValue));
Resultat:
mov rbx,400921FB54442D18h
movsd xmm3,mmword ptr [__real@43f0000000000000]
cvtsi2sd xmm1,rbx
test rbx,rbx
jns +7h
addsd xmm1,xmm3
xorpd xmm0,xmm0
movsd xmm0,xmm1
- Hier bleibt xmm0 auch über mehrere Verwendungen der Variable hinweg unangetastet; dafür …
- … verstehe ich nicht ansatzweise, was hier passiert: Sieht fast so aus, als konvertierte er die Integer-Konstante zur Gleitkommazahl, prüfe sie auf >0 (jump if not signed) und rechnete dann noch damit herum … lieber Gott der Latenz und Parallelisierung, was tust du mir an?!
- movsd ist stark entschärft, weil das Register hier vor der Verwendung genullt wird.
Gruß, Ky