kann diese funktion noch optimiert werden?
-
Hi,
ich habe eine funktion die äquivalent zu (int)floor(value) ist in assembler. die ist auch deutlich schneller als die normale mit dem cast. Problem ist nur das ich floor mehrere tausend male aufrufe und diese funktion jetzt nur noch der eigentliche bottleneck ist.
inline int Floor2Int( const float value ) { static int CtrlwdHolder; static int CtrlwdSetter; static int RetVal; __asm { fld value // push 'a' onto the FP stack fnstcw CtrlwdHolder // store FPU control word movzx eax, CtrlwdHolder // move and zero extend word into eax and eax, 0xFFFFF3FF // set all bits except rounding bits to 1 or eax, 0x00000400 // set rounding mode bits to round down mov CtrlwdSetter, eax // Prepare to set the rounding mode -- prepare to enter plaid! fldcw CtrlwdSetter // Entering plaid! fistp RetVal // Store floored and converted (to int) result fldcw CtrlwdHolder // Restore control word } return RetVal; }
kann man da nochwas rausholen? Gibts da evtl. was aus SSE oder geht das nur per FPU?
-
Saug dir bei Intel das Optimization Manual, da ist so eine Funktion drin.
Mit SSE geht's aber auch, soweit ich weiß.
-
vor fistp sollte man frndint aufrufen, damit auch was gerundet wird!
-
Power Off schrieb:
vor fistp sollte man frndint aufrufen, damit auch was gerundet wird!
nein.
inline unsigned short defaulCtrlW() { __asm { fnstcw word ptr [ esp - 4 ] movzx eax, word ptr [ esp - 4 ] } } inline int Floor2Int( const float value ) { static const unsigned short defaultCtrl = defaulCtrlW(); static const unsigned short floorCtrl = ( defaulCtrlW() & 0xf3ff ) | 0x0400; __asm { fld value fldcw floorCtrl fistp dword ptr [ esp - 4 ] fldcw defaultCtrl mov eax, [ esp - 4 ] } }
oder auch
inline void initMXCSR() { __asm { stmxcsr [ esp - 4 ] and [ esp - 4 ], 0xffff9ffff or [ esp - 4 ], 0xffff2ffff ldmxcsr [ esp - 4 ] } } inline int Floor2IntSSE(const float value) { __asm { cvtss2si eax, value } }
und am besten
#include "xmmintrin.h" inline void initMXCSR() { _MM_SET_ROUNDING_MODE( _MM_ROUND_DOWN ); } inline int Floor2IntSSE(const float value) { return _mm_cvtss_si32( _mm_load_ss( &value ) ); }
-
camper schrieb:
nein.
Echt jetzt? Davon steht aber nix in der Doku, jedenfalls wird's nicht ausdruecklich erwaehnt, nur in der Wertetabelle zum Befehl fistp steht, dass der Wert je nach Rundungsmodus unterschiedlich ausfallen kann. Komisch!
Wozu gibt's dann den frndint-Befehl ueberhaupt? Um Zwischenergebnisse zu runden?
-
na wenn das so in der dekumentation steht ist es doch eindeutig genug. frndint brauchst du eben, wenn du runden willst, aber es trotzdem ein gleitkommaformat bleiben soll.
-
Hi,
hab eine frage: was bewirkt das hier?
inline void initMXCSR() { __asm { stmxcsr [ esp - 4 ] and [ esp - 4 ], 0xffff9ffff or [ esp - 4 ], 0xffff2ffff ldmxcsr [ esp - 4 ] } }
?
-
dasselbe wie die entsprechende funktion mit intrinsics (du kannst sie ohne weiteres gegeneinanderaustauschen). das mxcsr register ist im grunde analog zum control register der fpu, nur etwas anders aufgebaut und die rc bits sind an anderer stelle. anders als die fpu register wird es allerdings nicht ständig durch den compiler geändert (was der grund ist, warum die fpu variante so langsam ist, der p4 z.b. ist darauf optimiert, zwischen zwei rundungsmodi (relativ = 14takte) schnell umzuschalten, und diese rundungsmodi sind normalerweise round to nearest (beim rechnen) und chop (beim cast zu int). du benutzt aber einen dritten modus, und das kostet (153 takte beim P4!!), man könnte also versucht sein, stattdessen round to nearest zu nehmen (default) und per bedingten sprung positive und negative werte getrennt zu behandeln, das müsste dann schneller sein.
weil mxcsr nicht ständig geändert wird, müsste es genügen diese funktion einmal aufzurufen und dann munter drauf los zu runden (was nur noch ein einzelner befehl ist).
-
nur mal so am rande: deine inline void initMXCSR() funktion veranlasst einen runtimeerror