Page 1 of 1

ASM and C-backend bswap16/32/64

Posted: Wed Jul 07, 2021 6:43 pm
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

Re: C-backend bswap16/32/64

Posted: Thu Jul 08, 2021 7:21 am
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

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

Posted: Fri Aug 26, 2022 11:05 am
by mk-soft
Update v1.02.0
- ASM and C-backend

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

Posted: Fri Aug 26, 2022 2:47 pm
by Mijikai
Thank you :)

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

Posted: Sat Aug 27, 2022 5:42 am
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


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

Posted: Sat Aug 27, 2022 12:30 pm
by mk-soft
Not sure, but it's probably not int128.
The structure m128 is not a int128. Low high byte notation.

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

Posted: Sat Aug 27, 2022 1:10 pm
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.

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

Posted: Tue Aug 30, 2022 11:06 am
by Olli
Is it possible to improve up to 64 bits ?
doc Intel - intrinsic for shuffle op

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

Posted: Wed Sep 07, 2022 3:27 am
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.

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

Posted: Wed Sep 07, 2022 6:34 am
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

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

Posted: Thu Sep 08, 2022 10:45 pm
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.

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

Posted: Wed Feb 14, 2024 1:38 am
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




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

Posted: Wed Feb 14, 2024 7:23 am
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.

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

Posted: Wed Feb 14, 2024 7:33 am
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