BSwap64/32/16

Share your advanced PureBasic knowledge/code with the community.
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

BSwap64/32/16

Post by Lunasole »

Hi again. Just coded that funny bicycle days ago to replace ASM-variants.
There already someone posted others (like using C lib swap functions), but let it be.

PS. Need bswap 8 also :mrgreen:

Code: Select all

; 2023     Lunasole
; v 1.0.0.1
; Inverts byte order (BE <> LE)
; RETURN:		inverted Quad/Long/Word
Procedure.q BSwap64(LL.q)
	ProcedureReturn 255&LL>>56|(255&LL)<<56|(255&LL>>48)<<8|(255&LL>>8)<<48|(255&LL>>40)<<16|(255&LL>>16)<<40|(255&LL>>32)<<24|(255&LL>>24)<<32
EndProcedure

Procedure.l BSwap32(L.l)
	ProcedureReturn 255&L>>24|(255&L)<<24|(255&L>>16)<<8|(255&L>>8)<<16
EndProcedure

Procedure.w BSwap16(S.w)
	ProcedureReturn 255&S>>8|(255&S)<<8
EndProcedure

CompilerIf #PB_Compiler_IsMainFile

	Define C.w = %1010011110010001
	Define B.l = %10100111100100011011000110001111
	Define A.q = %1010011110010001101100011000000110101101100000001110100110001001

	If C = BSwap16(BSwap16(C))
		Debug "OK16:"
	Else
		Debug "ERROR16:"
	EndIf
	Debug " 16:" + RSet(Bin(C, #PB_Word), 16, "0")
	Debug "S16:" + LSet(Bin(BSwap16(C), #PB_Word), 16, "0")
	Debug "d16:" + RSet(Bin(BSwap16(BSwap16(C)), #PB_Word), 16, "0")
	
	
	If B = BSwap32(BSwap32(B))
		Debug "OK32:"
	Else
		Debug "ERROR32:"
	EndIf
	Debug " 32:" + RSet(Bin(B, #PB_Long), 32, "0")
	Debug "S32:" + LSet(Bin(BSwap32(B), #PB_Long), 32, "0")
	Debug "d32:" + RSet(Bin(BSwap32(BSwap32(B)), #PB_Long), 32, "0")
	
	
	If A = BSwap64(BSwap64(A))
		Debug "OK64:"
	Else
		Debug "ERROR64:"
	EndIf
	Debug " 64:" + RSet(Bin(A, #PB_Quad), 64, "0")
	Debug "S64:" + LSet(Bin(BSwap64(A), #PB_Quad), 64, "0")
	Debug "d64:" + RSet(Bin(BSwap64(BSwap64(A)), #PB_Quad), 64, "0")
CompilerEndIf
Last edited by Lunasole on Thu Apr 13, 2023 10:51 am, edited 1 time in total.
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
infratec
Always Here
Always Here
Posts: 7576
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: BSwap64/32/16

Post by infratec »

Hi,

if I use your code in PB 6.00 x86 on Windows 10 x64 with:

Code: Select all

Debug RSet(Hex(BSwap16($1234), #PB_Unicode), 4, "0")
Debug RSet(Hex(BSwap32($12345678), #PB_Long), 8, "0")
Debug RSet(Hex(BSwap64($123456789ABCDEFF), #PB_Quad), 16, "0")
I get
3412
00563412
00DEBC9A78563412
You forgot some braces:

Code: Select all

(255&LL)<<56|(255&LL)>>56

Code: Select all

(255&L)<<24|(255&L)>>24
But since shift operations always fills the shifted bits with 0,
you can simply use this corrected version:

Code: Select all

; 2023     Lunasole
; Inverts byte order (BE <> LE)
; RETURN:		inverted Quad/Long/Word

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

Procedure.q BSwap64(LL.q)
	ProcedureReturn LL<<56|LL>>56|(255&LL>>48)<<8|(255&LL>>8)<<48|(255&LL>>40)<<16|(255&LL>>16)<<40|(255&LL>>32)<<24|(255&LL>>24)<<32
EndProcedure

Procedure.l BSwap32(L.l)
  ProcedureReturn L<<24|L>>24|(255&L>>16)<<8|(255&L>>8)<<16
EndProcedure

Procedure.w BSwap16(S.w)
	ProcedureReturn S>>8|S<<8
EndProcedure


CompilerIf #PB_Compiler_IsMainFile
 
  Debug RSet(Hex(BSwap16($1234), #PB_Unicode), 4, "0")
  Debug RSet(Hex(BSwap32($12345678), #PB_Long), 8, "0")
  Debug RSet(Hex(BSwap64($123456789ABCDEFF), #PB_Quad), 16, "0")
  
CompilerEndIf
Results in:
3412
78563412
FFDEBC9A78563412
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: BSwap64/32/16

Post by Lunasole »

infratec wrote: Thu Apr 13, 2023 7:23 am
Hm in this test your variant failed

Code: Select all

; 2023     Lunasole
; Inverts byte order (BE <> LE)
; RETURN:		inverted Quad/Long/Word
Procedure.q BSwap64(LL.q)
	ProcedureReturn (255&LL)<<56|255&LL>>56|(255&LL>>48)<<8|(255&LL>>8)<<48|(255&LL>>40)<<16|(255&LL>>16)<<40|(255&LL>>32)<<24|(255&LL>>24)<<32
EndProcedure

Procedure.l BSwap32(L.l)
	ProcedureReturn (255&L)<<24|255&L>>24|(255&L>>16)<<8|(255&L>>8)<<16
EndProcedure

Procedure.w BSwap16(S.w)
	ProcedureReturn 255&S>>8|(255&S)<<8
EndProcedure

;;;;
Procedure.q BSwap642(LL.q)
	ProcedureReturn LL<<56|LL>>56|(255&LL>>48)<<8|(255&LL>>8)<<48|(255&LL>>40)<<16|(255&LL>>16)<<40|(255&LL>>32)<<24|(255&LL>>24)<<32
EndProcedure

Procedure.l BSwap322(L.l)
  ProcedureReturn L<<24|L>>24|(255&L>>16)<<8|(255&L>>8)<<16
EndProcedure

Procedure.w BSwap162(S.w)
	ProcedureReturn S>>8|S<<8
EndProcedure


Define C.w = %1010011110010001
Define B.l = %10100111100100011011000110001111
Define A.q = %1010011110010001101100011000000110101101100000001110100110001001


If LSet(Bin(BSwap16(C), #PB_Word), 16, "0") = "1001000110100111"
	Debug "OK16"
Else
	Debug "ERROR16"
EndIf
Debug "SRC:" + LSet(Bin(C, #PB_Word), 16, "0")
Debug "B16:" + LSet(Bin(BSwap16(C), #PB_Word), 16, "0")
Debug "B162:" + LSet(Bin(BSwap162(C), #PB_Word), 16, "0")

If LSet(Bin(BSwap32(B), #PB_Long), 32, "0") = "10001111101100011001000110100111"
	Debug "OK32"
Else
	Debug "ERROR32"
EndIf
Debug "SRC:" + LSet(Bin(B, #PB_Long), 32, "0")
Debug "B32:" +  LSet(Bin(BSwap32(B), #PB_Long), 32, "0")
Debug "B322:" + LSet(Bin(BSwap322(B), #PB_Long), 32, "0")

If LSet(Bin(BSwap64(A), #PB_Quad),64,"0") = "1000100111101001100000001010110110000001101100011001000110100111"
	Debug "OK64"
Else
	Debug "ERROR64"
EndIf
Debug "SRC:" + LSet(Bin(A, #PB_Quad), 64, "0")
Debug "B64:" + LSet(Bin(BSwap64(A), #PB_Quad), 64, "0")
Debug "B642:" + LSet(Bin(BSwap642(A), #PB_Quad), 64, "0")
Output I get (your fixes are with extra 2)

Code: Select all

OK16
SRC:1010011110010001
B16:1001000110100111
B162:1111111110100111
OK32
SRC:10100111100100011011000110001111
B32:10001111101100011001000110100111
B322:11111111111111111111111110100111
OK64
SRC:1010011110010001101100011000000110101101100000001110100110001001
B64:1000100111101001100000001010110110000001101100011001000110100111
B642:1111111111111111111111111111111111111111111111111111111110100111
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: BSwap64/32/16

Post by Lunasole »

Lunasole wrote: Thu Apr 13, 2023 8:14 am Hm in this test your variant failed
While I see my even with some fixes fails on other values :mrgreen: Fk need more fixes and more complex expression
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
infratec
Always Here
Always Here
Posts: 7576
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: BSwap64/32/16

Post by infratec »

The main problem is, that PB does not have unsigned long and quad.
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: BSwap64/32/16

Post by Lunasole »

infratec wrote: Thu Apr 13, 2023 9:27 am The main problem is, that PB does not have unsigned long and quad.
Anyway those bit operations should work regardless of signed/unsigned, but well need to look better on this all, maybe I already forgot something hah
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: BSwap64/32/16

Post by Lunasole »

Seems fixed this craziness, the problem was with LShift/Rshift priority, now looks working as should 8) So I farted a bit like old fart.
Added also that test code.
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
infratec
Always Here
Always Here
Posts: 7576
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: BSwap64/32/16

Post by infratec »

There is still one problem:

If you define D.u and use your tests, it fails, because it compares now signed with unsigned.
To avoid this you need BSwap16w() and BSwap16u() with the correct return types.
User avatar
mk-soft
Always Here
Always Here
Posts: 6202
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: BSwap64/32/16

Post by mk-soft »

It was me with the bswap32 ;)
ASM und c-backend bswap32

Have you ever thought about doing it the way it is? Byte swap instead of bit shifting

Code: Select all

Structure ArrayOfByte
  b.b[0]
EndStructure

Procedure.l bswap32(Value.l)
  Protected *pVal.ArrayOfByte
  *pVal = @value
  Swap *pVal\b[0], *pVal\b[3]
  Swap *pVal\b[1], *pVal\b[2]
  ProcedureReturn Value
EndProcedure

Val.l = $FF1234EE
r1.l = bswap32(val)
Debug Hex(Val, #PB_Long) + " -> " + Hex(r1, #PB_Long)
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: BSwap64/32/16

Post by Lunasole »

infratec wrote: Thu Apr 13, 2023 12:12 pm There is still one problem:

If you define D.u and use your tests, it fails, because it compares now signed with unsigned.
To avoid this you need BSwap16w() and BSwap16u() with the correct return types.
That's right, needs to be changed like you said if needed. Or can use macro instead of procedures here.
mk-soft wrote: Thu Apr 13, 2023 12:18 pm It was me with the bswap32 ;)
ASM und c-backend bswap32

Have you ever thought about doing it the way it is? Byte swap instead of bit shifting
Yes, simply swap bytes is more obvious at all, just liked to play with this a bit^^
I've seen your variants somewhere in search when looked recently (maybe also someone's else in other topics).
What about ASM there is also +1 viewtopic.php?t=14524&hilit=BSwap
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
idle
Always Here
Always Here
Posts: 5835
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: BSwap64/32/16

Post by idle »

I would suggest this topic viewtopic.php?p=572356#p572356

The methodology your using is for unsigned types, and the main problem is with the << (shift arithmetic right)
You can do both 32 and 16 bit byte swaps in a quad and mask it off but you can't do the same for 64 bit with that method

Code: Select all


;Macro BSWAP64(v) 
;  v = ((v >> 8) & $00FF00FF00FF00FF) | ((v & $00FF00FF00FF00FF) << 8) ;flip adjacent bytes 
;  v = ((v >> 16) & $0000ffff0000ffff) | ((v & $0000ffff0000ffff) << 16) ; flip words 
;  v = (v >> 32) | (v << 32) ;flip dwords 
;EndMacro 

Macro BSWAP32(v) 
  vi.q = v 
  vi = ((vi >> 8) & $00FF00FF) | ((vi & $00FF00FF) << 8) ;flip adjacent bytes 
  vi = (vi >> 16) | vi << 16  ;flip words 
  v = vi & $FFFFFFFF
EndMacro 

Macro BSWAP16(v) 
  vi.q = v 
  vi = ((vi >> 8) & $00FF) | ((vi & $00FF) << 8) ;flip adjacent bytes 
  v = vi & $FFFF
EndMacro   

or you can use a dirty macro hack to enable unsigned but it only works fasm windows and linux

Code: Select all

 
;EnableUnsigned  v1.0a   
;Author Idle 25/3/16 
;Supports PB 5.42LTS Window, Linux  
;Unsigned arithmetic and logical comparisons for   
;x64: Long, Integer, Quads 
;x86: Long, Integer 
;Usage: 
;Scope unsigned arithmetic and logic in EnableUnsigned() DisableUnsigned() blocks
;EnableUnsigned()  
;if ux > uy  ; changes the operators to unsigned: supports < > <= >= <> =   
;    do something unsigned: supports * / + - << >>  
;  DisableUnsigned()
;   ;back to signed  
;EndIf 
;Disableunsigned() ;Note you can call Disableunsigned() where ever you need it 


CompilerIf SizeOf(integer) = 4
  
  
Macro EnableUnsigned() 
  
  !macro IDIV var
  !{ 
     !mov edx,0 
     !div var
  !}
  
  !macro IMUL reg,var
  !{
    !mov eax,reg 
    !mul var
    !mov reg,eax 
  !}  
  
  !macro SAR reg,var 
  !{
    !shr reg,var 
  !} 
  
  !macro SAL reg,var 
  !{ 
   !shl reg,var 
  !}
    
  !macro CDQ {} 
  
  !macro JG arg
  !{ 
  !JA arg 
  !}
  !macro JGE arg 
  !{ 
     !JAE arg 
  !}
  !macro JL arg 
  !{
     !JB arg 
  !}
  !macro JLE arg 
  !{ 
     !JBE arg 
  !}
  
EndMacro

Macro DisableUnsigned() 
  !purge IDIV
  !purge IMUL
  !purge SAR
  !purge SAL 
  !purge CDQ 
  !purge JG
  !purge JGE
  !purge JL
  !purge JLE
EndMacro 

CompilerElse 
   
  Macro EnableUnsigned() 
  
  !macro IDIV var
  !{ 
     !mov rdx,0 
     !div var
  !}
  
  !macro IMUL reg,var
  !{
  !match =qword x , var 
  !\{ mov rax, reg 
     !mov r15, var 
   !\} 
    !mul reg
    !mov reg,rax 
  !}  
  
  !macro SAR reg,var 
  !{
    !shr reg,var 
  !} 
  
  !macro SAL reg,var 
  !{ 
   !shl reg,var 
  !}
    
  !macro MOVSXD reg,var  
  !{ 
    !match =dword x , var 
    !\{ mov eax, var 
       !mov reg,rax \} 
    !} 
  !macro CQO {}
  !macro CDO {}
  !macro CWD {} 
  !macro CBW {}
  !macro CWDE{}
  !macro CDQE {} 
  !macro CDQ {} 
  
  !macro JG arg
  !{ 
  !JA arg 
  !}
  !macro JGE arg 
  !{ 
     !JAE arg 
  !}
  !macro JL arg 
  !{
     !JB arg 
  !}
  !macro JLE arg 
  !{ 
     !JBE arg 
  !}
  
EndMacro 

Macro DisableUnsigned() 
  !purge IDIV
  !purge IMUL
  !purge SAR
  !purge SAL 
  !purge MOVSXD
  !purge CQO 
  !purge CDO
  !purge CWD 
  !purge CBW
  !purge CWDE 
  !purge CDQE 
  !purge CDQ 
  !purge JG
  !purge JGE
  !purge JL
  !purge JLE
EndMacro   

CompilerEndIf   

Macro BSWAP64(v) 
  v = ((v >> 8) & $00FF00FF00FF00FF) | ((v & $00FF00FF00FF00FF) << 8) ;flip adjacent bytes 
  v = ((v >> 16) & $0000ffff0000ffff) | ((v & $0000ffff0000ffff) << 16);flip words 
  v = (v >> 32) | (v << 32) ;flip dwords 
EndMacro 

Macro BSWAP32(v) 
  v = ((v >> 8) & $00FF00FF) | ((v & $00FF00FF) << 8) ;flip adjacent bytes 
  v = (v >> 16) | v << 16  ;flip words 
EndMacro 

Macro BSWAP16(v) 
  v = ((v >> 8) & $00FF) | ((v & $00FF) << 8) ;flip adjacent bytes 
EndMacro   

Global vl.l = $fedcba12; // 32-bit word to reverse bit order
Global vi.i = $FEDCBA9876543210

EnableUnsigned() 

bswap32(vl) 
bswap64(vi) 

DisableUnsigned() 

Debug Hex(vl,#PB_Long)
Debug Hex(vi,#PB_Quad)

 
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: BSwap64/32/16

Post by Lunasole »

Anyway another one variant for this small question (I posted as didn't found here already), I like more this shifts-based idea like it is quite more optimized and there are no risks unless someone mess the types.
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
mk-soft
Always Here
Always Here
Posts: 6202
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: BSwap64/32/16

Post by mk-soft »

Lunasole wrote: Sun Apr 16, 2023 10:19 am Anyway another one variant for this small question (I posted as didn't found here already), I like more this shifts-based idea like it is quite more optimized and there are no risks unless someone mess the types.
Sorry,
But the most optimal method is to use the ASM code or __builtin_xyz.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: BSwap64/32/16

Post by Lunasole »

mk-soft wrote: Sun Apr 16, 2023 12:37 pm Sorry,
But the most optimal method is to use the ASM code or __builtin_xyz.
Yes. ASM is the most optimal, and I didn't said that this one is the most (this one is more optimal comparing to other methods like mentioned here before).
C builtin depends on optimizations probably (and maybe macro like this may be more optimal than calling C subs, maybe not), I haven't need to check this.
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: BSwap64/32/16

Post by Lunasole »

mk-soft wrote: Sun Apr 16, 2023 12:37 pm
Btw, you variant unfortunately also lacks BSwap8... It's hard to find solution for that.
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
Post Reply