[GCC] Inline Assembler und MMX
-
hi,
wieso ist diese mmx-assembler-version langsamer als der c-version? was mache ich falsch?
es sollen von 2 rgba-werten (32bit, unsigned long) die einzelnen farbkomponenten (r, g, b) miteinander multipliziert werden, danach wird der resultierende 16bit-wert durch 256 geteilt und wieder der farbkomponente zugewiesen.
wieso muss ich eigentlich immer ein doppeltes % vor die register schreiben?
unsigned long BlendMMX(const unsigned long TextureColor, const unsigned long MaskValue) { unsigned long Result; __asm__ ( "pxor %%mm7, %%mm7\n" // 0 "movd %1, %%mm0\n" // 32bit alpha in 64bit-mmx-register laden: 0|0|0|0|a|a|a|a (8x8bit) "movd %2, %%mm2\n" // mm0= *dst => 32bit farbe in 64bit-mmx-register lesen: 0|0|0|0|a|r|g|b (8x8bit) "punpcklbw %%mm7, %%mm0\n" // 0.a|0.a|0.a|0.a "punpcklbw %%mm7, %%mm2\n" // 8x8bit in 4x16bit mit 0 erweitern: 0|0|0|0|a|a|a|a -> 0.a|0.a|0.a|0.a "pmullw %%mm2, %%mm0\n" // 4x 16bit multiply: mm0= a*a2|r*a2|g*a2|b*a2 "psrlw $8, %%mm0\n" // mm0= 0.a|0.r|0.g|0.b (4x >>8) "packuswb %%mm7, %%mm0\n" // mm0= 0|0|0|0|a|r|g|b (8x8bit) "movd %%mm0, %0\n" // *dst= mm0 32bit-farbe schreiben "emms" // mmx-ende: fpu-register wieder herstellen : "=r" (Result) : "r" (TextureColor), "r" (MaskValue) : "mm0", "mm2", "mm7" ); return Result; }
struct RGB { // Datenstruktur union { struct { u_char b; u_char g; u_char r; u_char a; }; unsigned long color; }; } unsigned long Blend(const RGBA &TextureColor, const RGBA &MaskValue) { return ((TextureColor.r * MaskValue.r) >> 8) | (((TextureColor.g * MaskValue.g) >> 8) << 8) | (((TextureColor.b * MaskValue.b) >> 8) << 16); }
-
Ich würde vielleicht das Programm mit der "normalen" C-Funktion mit dem Schalter -S kompilieren:
gcc -S dein_programm.c -Ox
(-Ox ist deine Optimierungsstufe). Damit erzeugt gcc eine Assembler-Datei mit der Endung .s.
Dort kann man nachschauen, wie gcc die C-Funktion in Assembler kompiliert und mit deiner Assembler-Funktion vergleichen.
Ich erinnere mich dunkel, irgendwo gelesen zu haben, dass Assembler-Befehl emms ganz schön viele Takte benötigt (> 100???) und dass die Pipelines dabei "entleert" werden, weiß nicht genau ob das stimmt...
Ich denke, wie dem auch sei, kann man davon ausgehen, dass das ständige Umschalten mit emms Zeit kostet und das wird wohl der Grund sein, warum deine Funktion langsamer ist.
-
Hier http://www.agner.org/optimize/optimizing_assembly.pdf auf der Seite 131 im Kapitel 17.4 steht was über emms.
Wie es aussieht, kostet der Befehl nur auf Pentium Pro Prozessoren viel Zeit, ansonsten wird er schnell ausgeführt, hm...