ASM and C-backend bswap16/32/64

Share your advanced PureBasic knowledge/code with the community.
User avatar
mk-soft
Always Here
Always Here
Posts: 5406
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

ASM and C-backend bswap16/32/64

Post by mk-soft »

Before everyone searches for a long time :wink:

Update v1.02.0
- ASM and C-backend

Update v1.02.1
- added bswap128

Code: Select all

;-TOP by mk-soft, v1.02.1, 27.08.2022

CompilerIf #PB_Compiler_Version < 600
  #PB_Backend_Asm = 0
  #PB_Backend_C = 1
  #PB_Compiler_Backend = 0
CompilerEndIf

Procedure bswap16(value.u)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap16(v_value);
  CompilerElse
    !xor eax,eax
    !mov ax, word [p.v_value]
    !rol ax, 8
    ProcedureReturn
  CompilerEndIf
EndProcedure

Procedure bswap32(value.l)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap32(v_value);
  CompilerElse
    !mov eax, dword [p.v_value]
    !bswap eax
    ProcedureReturn
  CompilerEndIf
EndProcedure

Procedure.q bswap64(value.q)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap64(v_value);
  CompilerElse
    CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
      !mov rax, qword [p.v_value]
      !bswap rax
    CompilerElse
      !mov edx, dword [p.v_value]
      !mov eax, dword [p.v_value + 4]
      !bswap edx
      !bswap eax
    CompilerEndIf
    ProcedureReturn
  CompilerEndIf
EndProcedure

Structure int128 
  l.q
  h.q
EndStructure   

Procedure bswap128(*value.int128, *result.int128 = 0) ;idle 
   
  Protected low.q = *value\l  
  Protected high.q = *value\h 
  
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
     !v_high = __builtin_bswap64(v_high); 
     !v_low = __builtin_bswap64(v_low);
  CompilerElse
    CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
       !mov rdx,[p.v_high] 
       !mov rax,[p.v_low] 
       !bswap rax 
       !bswap rdx 
       !mov [p.v_low],rax 
       !mov [p.v_high],rdx 
    CompilerElse
       !mov edx, dword [p.v_high]
       !mov eax, dword [p.v_high + 4]
       !bswap edx
       !bswap eax
       !mov [p.v_high], dword eax 
       !mov [p.v_high + 4], dword edx 
       !xor eax,eax 
       !xor edx,edx 
       !mov edx, dword [p.v_low]
       !mov eax, dword [p.v_low + 4]
       !bswap edx
       !bswap eax
       !mov [p.v_low], dword eax 
       !mov [p.v_low + 4], dword edx 
    CompilerEndIf   
  CompilerEndIf
  If *result
    *result\h = low 
    *result\l = high
  Else
    *value\h = low 
    *value\l = high
  EndIf  
EndProcedure 

; ----

Macro HexW(_var_)
  RSet(Hex(_var_, #PB_Word), 4, "0")
EndMacro

Macro HexL(_var_)
  RSet(Hex(_var_, #PB_Long), 8, "0")
EndMacro

Macro HexQ(_var_)
  RSet(Hex(_var_, #PB_Quad), 16, "0")
EndMacro

; ****

CompilerIf #PB_Compiler_IsMainFile
  
  Define a1.q, r1.q
  
  Debug "bswap16"
  a1 = $1234
  r1 = bswap16(a1)
  Debug HexW(r1)
  
  Debug "bswap32"
  a1 = $01020304
  r1 = bswap32(a1)
  Debug HexL(r1)
  
  Debug "bswap64"
  a1 = $01020304AABBCCDD
  r1 = bswap64(a1)
  Debug HexQ(r1)
  
  Debug "bswap128"
  Define a128.int128, r128.int128 
  
  ;a128\h = $FFEEDDCCBBAA9988 : a128\l = $7766554433221100
  a128\h = $0011223344556677 : a128\l = $8899AABBCCDDEEFF
  
  ;ShowMemoryViewer(a128, 16) 
  bswap128(a128, r128) 
  Debug HexQ(a128\h) + HexQ(a128\l) 
  Debug HexQ(r128\h) + HexQ(r128\l) 
  ;ShowMemoryViewer(r128, 16) 
CompilerEndIf
Last edited by mk-soft on Sat Aug 27, 2022 2:04 pm, edited 3 times in total.
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
juergenkulow
Enthusiast
Enthusiast
Posts: 556
Joined: Wed Sep 25, 2019 10:18 am

Re: C-backend bswap16/32/64

Post by juergenkulow »

Code: Select all

; __builtin_bswap16 in gcc 
Procedure bswap16(value.u)
  ! return __builtin_bswap16(v_value);
EndProcedure

Define a = $1234
Debug Hex(bswap16(a))

CompilerIf Not Defined(PB_Compiler_Backend,#PB_Constant) 
  CompilerError "Please install PureBasic version >=6.00 Alpha2"
CompilerEndIf   
CompilerIf #PB_Compiler_Backend<>#PB_Backend_C
  CompilerError  "Use C Backend Compiler in Compiler-Option"
CompilerEndIf 
GCC Documentation 6.59 Other Built-in Functions
User avatar
mk-soft
Always Here
Always Here
Posts: 5406
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: ASM and C-backend bswap16/32/64

Post by mk-soft »

Update v1.02.0
- ASM and C-backend
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
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: ASM and C-backend bswap16/32/64

Post by Mijikai »

Thank you :)
User avatar
idle
Always Here
Always Here
Posts: 5096
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: ASM and C-backend bswap16/32/64

Post by idle »

I need a m128 swap so added it, could be improved. I guess

Code: Select all

;-TOP by mk-soft, v1.02.0, 26.08.2022

CompilerIf #PB_Compiler_Version < 600
  #PB_Backend_Asm = 0
  #PB_Backend_C = 1
  #PB_Compiler_Backend = 0
CompilerEndIf

Procedure bswap16(value.u)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap16(v_value);
  CompilerElse
    !xor eax,eax
    !mov ax, word [p.v_value]
    !rol ax, 8
    ProcedureReturn
  CompilerEndIf
EndProcedure

Procedure bswap32(value.l)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap32(v_value);
  CompilerElse
    !mov eax, dword [p.v_value]
    !bswap eax
    ProcedureReturn
  CompilerEndIf
EndProcedure

Procedure.q bswap64(value.q)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap64(v_value);
  CompilerElse
    CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
      !mov rax, qword [p.v_value]
      !bswap rax
    CompilerElse
      !mov edx, dword [p.v_value]
      !mov eax, dword [p.v_value + 4]
      !bswap edx
      !bswap eax
    CompilerEndIf
    ProcedureReturn
  CompilerEndIf
EndProcedure

Structure m128 
  h.q
  l.q 
EndStructure   

Procedure bswap128(*m.m128) ;idle 
   
  Protected h.q = *m\h 
  Protected l.q = *m\l  
  
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
     !v_h = __builtin_bswap64(v_h); 
     !v_l = __builtin_bswap64(v_l);
  CompilerElse
    CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
       !mov rdx,[p.v_h] 
       !mov rax,[p.v_l] 
       !bswap rax 
       !bswap rdx 
       !mov [p.v_l],rax 
       !mov [p.v_h],rdx 
    CompilerElse
       !mov edx, dword [p.v_h]
       !mov eax, dword [p.v_h + 4]
       !bswap edx
       !bswap eax
       !mov [p.v_h], dword eax 
       !mov [p.v_h+4], dword edx 
       !xor eax,eax 
       !xor edx,edx 
       !mov edx, dword [p.v_l]
       !mov eax, dword [p.v_l + 4]
       !bswap edx
       !bswap eax
       !mov [p.v_l], dword eax 
       !mov [p.v_l+4], dword edx 
             
    CompilerEndIf   
  CompilerEndIf  
  
  *m\h = l 
  *m\l = h 
    
EndProcedure 

; ----

Macro HexW(_var_)
  RSet(Hex(_var_, #PB_Word), 4, "0")
EndMacro

Macro HexL(_var_)
  RSet(Hex(_var_, #PB_Long), 8, "0")
EndMacro

Macro HexQ(_var_)
  RSet(Hex(_var_, #PB_Quad), 16, "0")
EndMacro

; ****

CompilerIf #PB_Compiler_IsMainFile
  
  Define a1.q
  
  a1 = $1234
  Debug HexW(bswap16(a1))
  
  a1 = $01020304
  Debug HexL(bswap32(a1))
  
  a1 = $01020304AABBCCDD
  Debug HexQ(bswap64(a1))
  
  Global a.m128 
 
 a\l = $0011223344556677 
 a\h = $8899aabbccddeeff
 
 Debug Hexq(a\l) + hexq(a\h) 
 bswap128(@a) 
 Debug Hexq(a\l) + hexq(a\h) 
   
CompilerEndIf

User avatar
mk-soft
Always Here
Always Here
Posts: 5406
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: ASM and C-backend bswap16/32/64

Post by mk-soft »

Not sure, but it's probably not int128.
The structure m128 is not a int128. Low high byte notation.
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
mk-soft
Always Here
Always Here
Posts: 5406
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: ASM and C-backend bswap16/32/64

Post by mk-soft »

Update v1.02.1
- Added bswap128

So the low-high-byte notation for int128 should be correct.

P.S.
Intel and Arm (default mode) processors using little-edianness.
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
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: ASM and C-backend bswap16/32/64

Post by Olli »

Is it possible to improve up to 64 bits ?
doc Intel - intrinsic for shuffle op
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: ASM and C-backend bswap16/32/64

Post by Olli »

:?
That is not a demand nor a wonder to get a source code. I ask you if the C backend maintains the access of AVX ops, through intrinsic which seems to be the required way.
User avatar
idle
Always Here
Always Here
Posts: 5096
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: ASM and C-backend bswap16/32/64

Post by idle »

It might even automatically do it if you specify the right flags, I haven't had time to look at it but you can get auto vectorization targeting avx for instance at O2
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: ASM and C-backend bswap16/32/64

Post by Olli »

idle wrote: Wed Sep 07, 2022 6:34 am It might even automatically do it if you specify the right flags, I haven't had time to look at it but you can get auto vectorization targeting avx for instance at O2
I have difficulties to believe it could be automatic.
The compiler won't detect the quantity of same executions, quantity which can be given by a variable.

You talk about flags : are you talking about compiler flags, or, more accurate C compiler directive ?

Thank you, anyway, for your approach, and the time you are searching to give more details.
User avatar
idle
Always Here
Always Here
Posts: 5096
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: ASM and C-backend bswap16/32/64

Post by idle »

changed asm to use movbe

Code: Select all

;-TOP by mk-soft, v1.02.0, 26.08.2022

CompilerIf #PB_Compiler_Version < 600
  #PB_Backend_Asm = 0
  #PB_Backend_C = 1
  #PB_Compiler_Backend = 0
CompilerEndIf

Procedure bswap16(value.u)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap16(v_value);
  CompilerElse
    !movbe ax,[p.v_value]
    ProcedureReturn
  CompilerEndIf
EndProcedure

Procedure bswap32(value.l)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap32(v_value);
  CompilerElse
    !movbe eax,[p.v_value]
    ProcedureReturn
  CompilerEndIf
EndProcedure

Procedure.q bswap64(value.q)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
    !return __builtin_bswap64(v_value);
  CompilerElse
    CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
      !movbe rax,[p.v_value]
    CompilerElse
      !movbe edx,[p.v_value]
      !movbe eax,[p.v_value + 4]
    CompilerEndIf
    ProcedureReturn
  CompilerEndIf
EndProcedure

Structure m128 
  StructureUnion
    a.a[16]
    u.u[8] 
    l.l[4]
    q.q[2]
  EndStructureUnion
EndStructure   

Procedure bswap128(*m.m128) ;idle 
    
  Protected h.q = *m\q[1] 
  Protected l.q = *m\q[0]  
  
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C
     !v_h = __builtin_bswap64(v_h); 
     !v_l = __builtin_bswap64(v_l);
  CompilerElse
    CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
       !movbe rdx,[p.v_h]
       !movbe rax,[p.v_l]
       !mov [p.v_l], rax 
       !mov [p.v_h], rdx
    CompilerElse
       !movbe edx,[p.v_h]
       !movbe eax,[p.v_h+ 4]
       !mov [p.v_h], dword eax 
       !mov [p.v_h+4], dword edx 
       !movbe edx,[p.v_l]
       !movbe eax,[p.v_l + 4]
       !mov [p.v_l], dword eax 
       !mov [p.v_l+4], dword edx 
   CompilerEndIf
   
  CompilerEndIf  
  
  *m\q[1] = l 
  *m\q[0] = h 
    
EndProcedure 

Macro HexW(_var_)
  RSet(Hex(_var_, #PB_Word), 4, "0")
EndMacro

Macro HexL(_var_)
  RSet(Hex(_var_, #PB_Long), 8, "0")
EndMacro

Macro HexQ(_var_)
  RSet(Hex(_var_, #PB_Quad), 16, "0")
EndMacro

Macro HexM128(_var_) 
  Hexq(_var_\q[0]) + hexq(_var_\q[1]) 
EndMacro   
 
; ****

CompilerIf #PB_Compiler_IsMainFile
  
  Define a1.q
  
  a1 = $1234
  Debug HexW(bswap16(a1))
  
  a1 = $01020304
  Debug HexL(bswap32(a1))
  
  a1 = $01020304AABBCCDD
  Debug HexQ(bswap64(a1))
  
  Global a.m128 
 
 a\q[0] = $0011223344556677 
 a\q[1] = $8899aabbccddeeff
 
 Debug HexM128(a)  
 bswap128(@a) 
 Debug HexM128(a)  
 
 
CompilerEndIf



wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: ASM and C-backend bswap16/32/64

Post by wilbert »

idle wrote: Wed Feb 14, 2024 1:38 am changed asm to use movbe
I'm curious about the reason behind the choice.

movbe is a nice instruction but only supported since about 2013.
At the moment my desktop computer from 2012 is still good enough for my needs.
I imagine I'm not the only one still using such an old computer.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
idle
Always Here
Always Here
Posts: 5096
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: ASM and C-backend bswap16/32/64

Post by idle »

wilbert wrote: Wed Feb 14, 2024 7:23 am
idle wrote: Wed Feb 14, 2024 1:38 am changed asm to use movbe
I'm curious about the reason behind the choice.

movbe is a nice instruction but only supported since about 2013.
At the moment my desktop computer from 2012 is still good enough for my needs.
I imagine I'm not the only one still using such an old computer.
I didn't realize it was only since 2013, it just made more sense for the construct in a procedure
Post Reply