Wie wird das Registerflagbei CMPSD gesetzt?
-
BTW:
cmovb eax, -1
cmovxx erlaubt keine immediate's - allgemein: CMOVcc r,r/m
-
stimmt, dann eben
sbb eax, eax
-
cld seta eax cmovb eax, -1
- 'seta eax' gibt es ebenfalls nicht: seta al oder ah.
- sbb eax,eax würde für den Fall !CARRY das gesetzte bit in al/ah löschen.
=>mov eax,0 seta al sbb eax,0
-
cmovb schrieb:
cld seta eax cmovb eax, -1
- 'seta eax' gibt es ebenfalls nicht: seta al oder ah.
- sbb eax,eax würde für den Fall !CARRY das gesetzte bit in al/ah löschen.
=>mov eax,0 seta al sbb eax,0
Warum diese Reihenfolge. Hier wird immer -1 rauskommen oder etwa nicht?
Ich brauche jetzt auch noch eine Funktion zum String-Vergleich. Grundsätzlich kann ich da ja genau so verfahren (abgesehen davon, dass ich eine "logisches" big endian byte order habe.
Was mir allerdings Probleme macht ist, wenn die Strings nicht alle Chars auf Upper/Lower Case haben, sondern Groß-/Kleinschreibung enthalten. Wie kann ich das am besten lösen?Ich will keine Reihenfolge dieser Art haben:
ABC
Bertha
Omega
alpha
-
FrEEzE2046 schrieb:
Warum diese Reihenfolge. Hier wird immer -1 rauskommen oder etwa nicht?
Warum? Nochmal drüber nachdenken, wie jede Instruktion die Flags beeinflusst.
Eigentlich hatte ich gehofft, eine Instruktion einsparen zu können - eine Instruktion pro mögliches Ergebnis ist nicht besonders schön. Geht wohl doch nicht. Das mov könnte man noch durch xor ersetzen
push edi push esi lea esi, [eax+ecx-1] lea edi, [edx+ecx-1] std mov edx, ecx shr edx, 2 and ecx, 3 xor eax, eax repe cmpsb jne @@Exit mov ecx, edx lea esi, [esi-3] lea edi, [edi-3] repe cmpsd @@Exit: cld seta al sbb eax, 0 pop esi pop edi
-
mov eax,0 seta al sbb eax,0
1. Zeile: mov eax, 0: Schreibet 0 in eax
2. Zeile: seta (set byte on condition / if above) al: Wenn höher dann 1
3. Zeile: sbb (subtraction with borrow), 0: Wenn Carry-Flag gesetzt um 1 weiter dekrementieren.mmmh...
-
FrEEzE2046 schrieb:
Was mir allerdings Probleme macht ist, wenn die Strings nicht alle Chars auf Upper/Lower Case haben, sondern Groß-/Kleinschreibung enthalten. Wie kann ich das am besten lösen?
Es gibt mehrere Möglichkeiten, z.B. kann erst einmal ein
repe cmps
durchführen, und bei Ungleichheit zusätzlich prüfen, ob die Ungleichheit nur auf Unterschiede zwischen Groß und Klein zurückzuführen ist, und den Vergleich dann ggf. fortsetzen. Auch hier ist die Optimierung per cmpsd denkbar.
-
camper schrieb:
durchführen, und bei Ungleichheit zusätzlich prüfen, ob die Ungleichheit nur auf Unterschiede zwischen Groß und Klein zurückzuführen ist, und den Vergleich dann ggf. fortsetzen. Auch hier ist die Optimierung per cmpsd denkbar.
Danke für deine Antwort.
Was mir aufgefallen ist:
seta al sbb eax, 0
liefert die Ergebnisse genau falsch rum^^. Daher meine bedenken.
-
FrEEzE2046 schrieb:
seta al sbb eax, 0
liefert die Ergebnisse genau falsch rum^^.
esi/edi wurden auch vertauscht.
-
Ich habe dazu noch mal eine generelle Frage:
Wo ist eigentlich der Unterschied zwischen:
lea edi, [eax+ecx-1]
und
mov edi, eax add edi, ecx dec edi
Muss der Prozessor nicht immer die Schritte von "2" durchführen? Im Endeffekt ist "1" doch nur eine kürzere Schreibweise oder bringt dass tatsächlich auch sonst noch was?
EDIT:
Warum sind bei mir die Ergebniswerte vertauscht (1 u. -1)? Ich mach doch nicht viel anders als du:function __MemCompare__LE_DF__(const lho, rho; size: DWORD): Integer; assembler; asm { EAX -> lho result = 0 equal EDX -> rho result = 1 lho < rho ECX -> size result = -1 lho > rho } push edi push esi push ebx std // set direction flag to decrement mov edi, eax mov esi, edx xor eax, eax // null result mov ebx, ecx // save value shr ecx, 2 // look for dword align jz @@Rest mov edx, ebx sub edx, 4 add edi, edx // position on last dword add esi, edx repe cmpsd jne @@Exit @@Rest: mov ecx, ebx and ecx, 3 jz @@Exit add edi, ecx // byte offset add esi, ecx repe cmpsb @@Exit: cld seta al sbb eax, 0 pop ebx pop esi pop edi end; (* of MemCompare *) (* ------------------------------------------------------------------------------------ *)
-
FrEEzE2046 schrieb:
Muss der Prozessor nicht immer die Schritte von "2" durchführen? Im Endeffekt ist "1" doch nur eine kürzere Schreibweise oder bringt dass tatsächlich auch sonst noch was?
Mit lea ist es wahrscheinlich schneller, zudem werden keine Flags beeinflusst.
-
camper schrieb:
FrEEzE2046 schrieb:
Muss der Prozessor nicht immer die Schritte von "2" durchführen? Im Endeffekt ist "1" doch nur eine kürzere Schreibweise oder bringt dass tatsächlich auch sonst noch was?
Mit lea ist es wahrscheinlich schneller, zudem werden keine Flags beeinflusst.
Ich hab mal meinen Beitrag editiert. Weißt du woran es liegen kann?
-
FrEEzE2046 schrieb:
camper schrieb:
FrEEzE2046 schrieb:
Muss der Prozessor nicht immer die Schritte von "2" durchführen? Im Endeffekt ist "1" doch nur eine kürzere Schreibweise oder bringt dass tatsächlich auch sonst noch was?
Mit lea ist es wahrscheinlich schneller, zudem werden keine Flags beeinflusst.
Ich hab mal meinen Beitrag editiert. Weißt du woran es liegen kann?
Weil due esi/edi andersherum initialisierst, nebenbei fehlt bei dir noch die Adresskorrektur vor @@Rest.
-
camper schrieb:
Ich hab mal meinen Beitrag editiert. Weißt du woran es liegen kann?
Weil due esi/edi andersherum initialisierst, nebenbei fehlt bei dir noch die Adresskorrektur vor @@Rest.[/quote]
Du hast recht danke.
Zur Adresskorrektur:
add edi, ecx // byte offset add esi, ecx
mache ich doch.
EDIT:
Also, sieht jetzt so aus:
push edi push esi std // set direction flag to decrement lea esi, [edx+ecx] lea edi, [eax+ecx] xor eax, eax // null result mov edx, ecx // save value shr ecx, 2 // look for dword align jz @@Rest lea esi, [esi-4] // position on last DWORD lea edi, [edi-4] repe cmpsd jne @@Exit @@Rest: mov ecx, edx and ecx, 3 // remaining bytes jz @@Exit lea esi, [esi+ecx] // byte offset lea edi, [edi+ecx] repe cmpsb @@Exit: cld seta al sbb eax, 0 pop esi pop edi
Noch 2 Sachen dazu:
1. Lohnen sich die Vergleiche inkl. jump oder sollte ich lieber (so wie du) einfach cmpsb/d drüber laufen lassen, auch wenn in ecx 0 steht?
2. Bei mir sind die Ergebniswerte immer noch vertauscht. Verstehe ich nicht wirklich.
-
FrEEzE2046 schrieb:
Zur Adresskorrektur:
add edi, ecx // byte offset add esi, ecx
mache ich doch.
Woher weisst du, dass in ecx genau siezof(dword)-sizeof(byte)=3 drin steht? Abgesehen davon passt das mit dem Fall size<=3 ohnehin nicht.
-
camper schrieb:
FrEEzE2046 schrieb:
Zur Adresskorrektur:
add edi, ecx // byte offset add esi, ecx
mache ich doch.
Woher weisst du, dass in ecx genau siezof(dword)-sizeof(byte)=3 drin steht?
Ich weiß, dass in ecx die restlichen Bits sind, welche nicht dword aligned sind und die addiere ich drauf. Ist doch korrekt würde ich sagen.
-
FrEEzE2046 schrieb:
Ist doch korrekt würde ich sagen.
Dann schau dir nochmal mein Beispiel auf der ersten Seite an. ecx hätte dort den Wert 2, die Korrektor würde dazu führen, dass esi, edi zum Anfang der Strings zeigen.
Da noch zwei Zeichen zu vergleichen sind, vergleichst du das ersten Zeichen und das Zeichen davor (welches schon nicht mehr dazugehört), während das zweite Stringelement übersprungen wird.
-
camper schrieb:
FrEEzE2046 schrieb:
Ist doch korrekt würde ich sagen.
Dann schau dir nochmal mein Beispiel auf der ersten Seite an.
Hab ich wirklich zu genüge. Kannst du mir bitte den Fehler zeigen? Ich bin anscheinend blind dafür.
EDIT: Wovon sprichst du jetzt eigentlich? Den Byte Offset wiederherstellen oder esi/edi initialisieren
-
siehe Edit oben
-
camper schrieb:
siehe Edit oben
Irgendwie stimmt jetzt irgendwas überhaupt nicht. Vorher hat es funktioniert, jetzt habe ich es "kaputt optimiert"
var s1, s2 : String[6]; begin s1 := 'aaaaaa'; s2 := 'aaaaaa'; writeln(MemCmp(s1[1], s2[2], 6));
1. Ich stehe an Position s1[1] = Speicheradresse: 4458497
2. Ich führe auslea esi, [eax+ecx]
und stehe auf: 4458503
3. Da ich mich auf dem letzten DWORD positionieren möchte, führe ich auslea esi, [esi-4]
und stehe auf: 4458499
4. Jetzt führe ich aus:repe cmpsb
und
jne @@Exit
führt mich zur Exit-Marke, obwohl der Vergleich eigentlich "equals" hätte ergeben müssen.
Was läuft da schief?