A procedure that changes the bytes (low / high) of a Word variable

I have this procedure that changes the bytes (low / high) of a Word variable (it performs the same functions as the System.Swap function). This procedure works when compiler optimization is turned off but not turned on. Can someone help me with this?

procedure SwapWord(VAR TwoBytes: word); asm Mov EBX, TwoBytes Mov AX, [EBX] XCHG AL,AH Mov [EBX], AX end; 
+7
source share
5 answers

Fastest:

 function ReverseWord(w: word): word; asm {$IFDEF CPUX64} mov rax, rcx {$ENDIF} xchg al, ah end; 

If you also want to undo DWORD:

 function ReverseDWord(dw: cardinal): cardinal; asm {$IFDEF CPUX64} mov rax, rcx {$ENDIF} bswap eax end; 
+8
source

You cannot use the EBX register in ASM code without saving / restoring it. Adjusted version of your code

 procedure SwapWord_Working(VAR TwoBytes: word); asm PUSH EBX // save EBX Mov EBX, TwoBytes Mov AX, [EBX] XCHG AL,AH Mov [EBX], AX POP EBX // restore EBX end; 
+8
source

I am a little surprised that no one mentioned the absolute “hack”, which has existed for more than a decade, but does not get too much attention ... anyway here are my two cents

 function SwapWordBytes(const Value: Word): Word; var // shares memory with Value parameter LMemValue: array[0..1] of Byte absolute Value; // shares memory with Result LMemResult: array[0..1] of Byte absolute Result; begin LMemResult[0] := LMemValue[1]; LMemResult[1] := LMemValue[0]; end; 
+7
source

Do you consider using the Swap compiler function?

 procedure TForm1.FormCreate(Sender: TObject); var a: word; begin a := $1234; a := Swap(a); Caption := IntToHex(a, 4) end; 

If not, you don't need ASM for this (and ASM probably won't be available in 64-bit Delphi). You can just do

 procedure MySwap(var a: word); var tmp: byte; begin tmp := PByte(@a)^; PByte(@a)^ := PByte(NativeUInt(@a) + sizeof(byte))^; PByte(NativeUInt(@a) + sizeof(byte))^ := tmp; end; procedure TForm1.FormCreate(Sender: TObject); var a: word; begin a := $123456; MySwap(a); Caption := IntToHex(a, 4) end; 

and, of course, there are a million variants of this topic.

 procedure MySwap(var a: word); var tmp: byte; type PWordRec = ^TWordRec; TWordRec = packed record byte1, byte2: byte; end; begin with PWordRec(@a)^ do begin tmp := byte1; byte1 := byte2; byte2 := tmp; end; end; 

and, very briefly,

 procedure MySwap(var a: word); begin a := word(a shl 8) + byte(a shr 8); end; 

or

 procedure MySwap(var a: word); begin a := lo(a) shl 8 + hi(a); end; 
+5
source

Although Serg's answer is certainly correct, as stated in the comments on Serg's answer, it is ineffective. The fastest of these will obviously be the code provided in Gabr's answer, but since you explicitly want the procedure, not the function, to be the preferred version of the Serg procedure:

 procedure SwapWord_Working2 (VAR TwoBytes: word); asm mov dx, [TwoBytes] ;//[TwoBytes] = [eax] on x86 *[Note1] xchg dl, dh mov [TwoBytes], dx end; 

[Note1:] The serg version of the function will most likely not work for the upcoming x64 Delphi compiler. Assuming Embarcadero is sticking to its plan (mentioned somewhere by Allen Bauer) to use the Win64 calling convention (where @TwoBytes will be transmitted via RCX ), the version provided in this answer should still work on x64.

+1
source

All Articles