[MMX] Groß- in Kleinbuchstaben umwandeln
-
Ich soll mit Hilfe von MMX 16 chars von Groß- in Kleinbuchstaben umwandeln. Um nur einen Vergleich statt Zweien (c>='A' && c<='Z') zu benötigen soll folgende Äquivalenz angewendet werden (wir gratulieren zu obfuscated grade 3)...
min('Z'+1+min_t-'A' > c+min_t-'A' ? 0xff : 0 , 'a'-'A') min_t := -128 // ich wandle das mal möglichst fertig um: min(-102 > c+63 ? 0xff : 0, 32) -102 = 0x9A 63 = 0x3F 32 = 0x20
Da es genau 16 chars (=128 bit) sind sollte das MMX ohne Schleife lösen können. Allerdings habe ich dazu noch ein paar Fragen:
(1) die mmx-register sind 128 bit breit, wie schiebe ich da mit mov etwas rein? movq reicht ja nur für 64bit...habs trotzdem mal mit movq gemacht...
# at&t-syntax (hoffe dass bei mmx dann auch src-dest gilt) movq %rdi, %xmm0 # Ist das notwendig, kann also mmx nur darauf arbeiten? # zu allen die 63 addieren movq $0x3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F %xmm8 # tut man das so? paddb %xmm8 %xmm0 # jetzt die -102 irgendwo reinsetzen movq $0x9A9A9A9A9A9A9A9A9A9A9A9A9A9A9A9A %xmm9 #sieht mir immer noch nach wtf-code aus # jetzt endlich spaßig vergleichen pcmpgtb %xmm0 %xmm9 # Vergleich durchführen # jetzt das minimum machen, also wieder zuerst was reinschreiben movq $0x20... %xmm10 pminsb %xmm9 %xmm10 # und jetzt steht eh schon der wert der zu addieren ist in xmm10 paddb %xmm10 %xmm0 # und wieder zurückgeben movq %xmm0 %rax #hier macht es ja boom in rax, wie kann ich denn das nun überhaupt wieder byteweise rauskopieren in den string...doch schleife??
Außerdem ist der String der da reinkommt ja eine adresse...ich sollte die ja zuerst auflösen bevor ich sie da reinkopiere...
Wie ihr seht habe ich an der Schnittstelle MMX<->Normales ASM noch Probleme. Außerdem interessiert es mich natürlich ob mein Ansatz überhaupt so funktionieren kann...
Auf etwas Unterstützung hoffend...
MfG SideWinder
-
hi,
du meinst wohl SSEx(=16bit Reg.) und nicht MMX(64Bit Reg.). Glücklicherweise kann man aber sowohl bei den SSEx Befehlen als auch bei den MMX befehlen die xmm-Register verwenden (mmx Reg. gehen auch). Kannst dich ja mal bei Wiki über die Geschichte schlau machen
Bei der Verwendung von SIMD Befehlen ist das aligment sehr wichtig (Speicheroperanten müssen align 16 sein) – Wenn die Daten nicht align 16 sind, geht eine Menge an Geschwindigkeit verloren. Bei Strings kommt noch das Problem dazu, dass man eventuell Daten hinter dem String-Ende mit bearbeitet. Dies kann man zwar umgehen, macht die Sache aber etwas komplizierter (pcmpeqb, pmovmskb und bsf sind hier bei dann Hilfreich).
Hier mal eine einfache Variante die von davon ausgeht das ECX die Anzahl der 16 Byte Blöcke enthält und ESI der Zeiger auf den String ist (Intel-Systax,masm):.data align 16 string db "HALLO WELT WIE AbCDefgHiJ xYZ" align 16 ; zwingend notwendig! msk_A OWORD 40404040404040404040404040404040h msk_Z OWORD 5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5Ah msk_add OWORD 20202020202020202020202020202020h .code mov esi,OFFSET string mov ecx,2 ; ESI enthält Adresse des Strings. ECX die Anzahl der XMMWORDs. ; Damit die Sache auch effizient ist, muss die Adresse align 16 sein! ; (Wenn dem nicht so wäre, müsste man movdqu (u=unaligned) statt movdqa nehmen) align 8 ; optional ;) @loop: movdqa xmm0,OWORD ptr [esi] ; lade 16 byte nach xmm0 (alternativ movdqu) movdqa xmm1,xmm0 movdqa xmm2,xmm0 pcmpgtb xmm1,msk_A ; vergleich x >= 'A' pcmpgtb xmm2,msk_Z ; vergleich x > 'Z' pandn xmm2,xmm1 ; (~xmm2)&xmm1 pand xmm2,msk_add ; alle Bytes die Großbuchstaben enthielten, ; sind jetzt mit 0xff gefüllt -> maskieren mit 0x20 paddb xmm0,xmm2 ; addiere 0x20 zu Großbuchstaben movdqa OWORD ptr [esi],xmm0 ; Ergebniss sichern (alternativ movdqu) lea esi,[esi+16] dec ecx jnz @loop
-
Danke movdqa ist schon mal ein guter Befehl.
Bei mir sind diese 16 chars ein fixer Wert. Also ich habe da keinen Dinge hinter dem String auf die ich aufpassen müsste. Auch sollte ich deshalb keine Loop brauchen.
Danke jedenfalls schonmal, auch für die Hinweise mit dem Konstanten definieren. Ich denke das bringt mich mal weiter
Edit:
.code ist nichts anderes als .text?MfG SideWinder
-
SideWinder schrieb:
.code ist nichts anderes als .text?
Würde ich mal von ausgehen. Ist einfach der wechsel ins code-Segment.
-
Also mit Debug geht so eine Umwandlung ganz einfach, mit z.B.:
or Al,20
d.h.:
z.B.
0100 0001
or
0010 00000110 0001
Aber ich bin auch verwirrt: ich dachte MMX benutzt die maximal 80Bit breiten
FPU Register und beschneidet sie auf 64bit inclusive Saturation/Wrap Around
während 128Bit-Breite und breiter erst mit SSE möglich ist.
Tut mir leid, falls die Antwort zu voreilig ist, habe selber noch nicht so viel
mit >16 Bit zu tun, und ich brüte derzeit frustriert über die Schnittstelle zur Soundausgabe
(für ein einfaches Morsezeichenproggi) ...
-
derSchüler schrieb:
ich dachte MMX benutzt die maximal 80Bit breiten
FPU Register und beschneidet sie auf 64bit inclusive Saturation/Wrap Around
während 128Bit-Breite und breiter erst mit SSE möglich ist.MMX benutz die untern 64 Bit der Fpu-Register - da wird nichts von 80 Bit runter gebrochen. Als SSE1 eingeführt wurde, hat Intel den MMX-Befehlen den Zugriff auf XMM-Register ermöglicht, und umgekehrt auch erlaubt mit den neuen SSE1 Befehlen auf die MMX Register zuzugreifen.