Bitshift and Rotation

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

Bitshift and Rotation

Post by mk-soft »

No Comment :wink:

Update v1.02
- Added SignX(...) for Byte, Word, etc

Update v1.03
- Added 32bit Compiler version

Update v1.04
- optimize code, Thanks to Wilbert

Update v1.05
- Added Get, Set and ClrBit

Update v1.06
- Added x64

Code: Select all

;-TOP
; Kommentar     : Bitshift and Rotation
; Author        : mk-soft
; Second Author : 
; Datei         : Bitshift.pb
; Version       : v1.06
; Erstellt      : 09.06.2007
; Geändert      : 25.06.2017
; 
; Compilermode  :
;
; ***************************************************************************************

; Bitshift left shift
Procedure SHL8(value.b, count.l = 1)

  !xor eax, eax
  !mov al, byte [p.v_value]  
  !mov ecx, dword [p.v_count]
  !shl al, cl
  ProcedureReturn
  
EndProcedure

; Bitshift right shift
Procedure SHR8(value.b, count.l = 1)

  !xor eax, eax
  !mov al, byte [p.v_value]  
  !mov ecx, dword [p.v_count]
  !shr al, cl
  ProcedureReturn
  
EndProcedure

; Bitshift left shift
Procedure SHL16(value.w, count.l = 1)

  !xor eax, eax
  !mov ax, word [p.v_value]  
  !mov ecx, dword [p.v_count]
  !shl ax, cl
  ProcedureReturn
  
EndProcedure

; Bitshift right shift
Procedure SHR16(value.w, count.l = 1)

  !xor eax, eax
  !mov ax, word [p.v_value]  
  !mov ecx, dword [p.v_count]
  !shr ax, cl
  ProcedureReturn
  
EndProcedure

; Bitshift left shift
Procedure SHL32(value.l, count.l = 1)

  !mov eax, dword [p.v_value]  
  !mov ecx, dword [p.v_count]
  !shl eax, cl
  ProcedureReturn
  
EndProcedure

; Bitshift right shift
Procedure SHR32(value.l, count.l = 1)

  !mov eax, dword [p.v_value]  
  !mov ecx, dword [p.v_count]
  !shr eax, cl
  ProcedureReturn
  
EndProcedure

; Bitshift left shift
Procedure.q SHL64(value.q, count.q = 1);   Bitshift left shift
  
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rax, qword [p.v_value]
    !mov rcx, qword [p.v_count]
    !shl rax, cl
    ProcedureReturn
  CompilerElse
    ProcedureReturn value<<count
  CompilerEndIf
  
EndProcedure

; Bitshift right shift
Procedure.q SHR64(value.q, count.q = 1);   Bitshift right shift
  
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rax, qword [p.v_value]
    !mov rcx, qword [p.v_count]
    !shr rax, cl
    ProcedureReturn
  CompilerElse
    Protected v1.q
    v1 = ~($FFFFFFFFFFFFFFFF << (64-count))
    ProcedureReturn value>>count & v1
  CompilerEndIf
  
EndProcedure

; Bitshift left rotation
Procedure ROL32(value.l, count.l = 1)

  !mov eax, dword [p.v_value]  
  !mov ecx, dword [p.v_count]
  !rol eax, cl
  ProcedureReturn
  
EndProcedure

; Bitshift right rotation
Procedure ROR32(value.l, count.l = 1)

  !mov eax, dword [p.v_value]  
  !mov ecx, dword [p.v_count]
  !ror eax, cl
  ProcedureReturn
  
EndProcedure

; Bitshift left rotation
Procedure.q ROL64(value.q, count.q = 1);   Bitshift left rotation
  
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rax, qword [p.v_value]
    !mov rcx, qword [p.v_count]
    !rol rax, cl
    ProcedureReturn
  CompilerElse
    Protected v1.q = shr64(value, 64-count)
    ProcedureReturn (value<<count) | v1
  CompilerEndIf
  
EndProcedure

; Bitshift right rotation
Procedure.q ROR64(value.q, count.q = 1);   Bitshift right rotation
  
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rax, qword [p.v_value]
    !mov rcx, qword [p.v_count]
    !ror rax, cl
    ProcedureReturn    
  CompilerElse
    Protected v1.q = shr64(value, count)
    ProcedureReturn v1 | value<<(64-count)
  CompilerEndIf
  
EndProcedure

; Swap Bytes
Procedure.w BSWAP16(value.w)
  !xor eax,eax
  !mov ax, word [p.v_value]
  !rol ax, 8
  ProcedureReturn
EndProcedure

Procedure BSWAP32(value.l)
  !mov eax, dword [p.v_value]
  !bswap eax
  ProcedureReturn
EndProcedure

Procedure.q BSWAP64(value.q)
  
  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
  
EndProcedure

; -------------------------------------------------------------------------------------

Macro SignB(Value)
  (Bool(Value > 0) - Bool(Value >> 7))
EndMacro

Macro SignW(Value)
  (Bool(Value > 0) - Bool(Value >> 15))
EndMacro

Macro SignL(Value)
  (Bool(Value > 0) - Bool(Value >> 31))
EndMacro

Macro SignQ(Value)
  (Bool(Value > 0) - Bool(Value >> 63))
EndMacro

; -------------------------------------------------------------------------------------

Procedure GetBit32(value, bit)
    !mov eax, dword [p.v_value]
    !mov ecx, dword [p.v_bit]
    !bt eax, ecx
    !rcl eax, 1
    !and eax, 1
    ProcedureReturn
EndProcedure

Procedure GetBit64(value.q, bit.q)
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rax, qword [p.v_value]
    !mov rcx, qword [p.v_bit]
    !bt rax, rcx
    !rcl rax, 1
    !and rax, 1
    ProcedureReturn
  CompilerElse
    ProcedureReturn value>>bit & 1
  CompilerEndIf  
  ProcedureReturn
EndProcedure

Procedure SetBit32(value, bit)
    !mov eax, dword [p.v_value]
    !mov ecx, dword [p.v_bit]
    !bts eax, ecx
    ProcedureReturn
EndProcedure

Procedure.q SetBit64(value.q, bit.q)
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rax, qword [p.v_value]
    !mov rcx, qword [p.v_bit]
    !bts rax, rcx
    ProcedureReturn
  CompilerElse
    ProcedureReturn (1 << bit) | value
  CompilerEndIf  
  ProcedureReturn
EndProcedure

Procedure ClrBit32(value, bit)
    !mov eax, dword [p.v_value]
    !mov ecx, dword [p.v_bit]
    !btr eax, ecx
    ProcedureReturn
EndProcedure

Procedure.q ClrBit64(value.q, bit.q)
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rax, qword [p.v_value]
    !mov rcx, qword [p.v_bit]
    !btr rax, rcx
    ProcedureReturn
  CompilerElse
    ProcedureReturn ~(1 << bit) & value
  CompilerEndIf  
  ProcedureReturn
EndProcedure

Procedure ToggleBit32(value, bit)
    !xor eax, eax
    !mov ecx, dword [p.v_bit]
    !bts eax, ecx
    !mov ecx, dword [p.v_value]
    !xor eax, ecx
    ProcedureReturn
EndProcedure

Procedure.q ToggleBit64(value.q, bit.q)
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !xor rax, rax
    !mov rcx, qword [p.v_bit]
    !bts rax, rcx
    !mov rcx, qword [p.v_value]
    !xor rax, rcx
    ProcedureReturn
  CompilerElse
    ProcedureReturn (1 << bit) ! value
  CompilerEndIf  
  ProcedureReturn
EndProcedure

; ***************************************************************************************

CompilerIf #PB_Compiler_IsMainFile
  
  x.q
  
  ;-Test
  Debug "shr8(x,2)"
  x = $80
  Debug RSet(Bin(x),8,"0")
  x = shr8(x,2)
  Debug RSet(Bin(x),8,"0")
  
  Debug "shl8(x,2)"
  x = $02
  Debug RSet(Bin(x),8,"0")
  x = shl8(x,2)
  Debug RSet(Bin(x),8,"0")
  
  Debug "bswap16"
  x = $0102
  Debug RSet(Hex(x),8,"0")
  x = bswap16(x)
  Debug RSet(Hex(x),8,"0")
  
  Debug "bswap32"
  x = $01020304
  Debug RSet(Hex(x),8,"0")
  x = bswap32(x)
  Debug RSet(Hex(x),8,"0")
  
  Debug "bswap64"
  x = $0102030405060708
  Debug RSet(Hex(x),16,"0")
  x = bswap64(x)
  Debug RSet(Hex(x),16,"0")
  
  Debug "shl32(x,4)"
  x = %1001
  Debug RSet(Bin(x), 32, "0")
  x = shl32(x, 4)
  Debug RSet(Bin(x), 32, "0")
  
  Debug "shr32(x,4)"
  x = %1001
  Debug RSet(Bin(x), 32, "0")
  x = shr32(x, 4)
  Debug RSet(Bin(x), 32, "0")
  
  Debug "rol32(x,29)"
  x = %1001
  Debug RSet(Bin(x), 32, "0")
  x = rol32(x, 29)
  Debug RSet(Bin(x), 32, "0")
  
  Debug "ror32(x,5)"
  x = %1001
  Debug RSet(Bin(x), 32, "0")
  x = ror32(x, 5)
  Debug RSet(Bin(x), 32, "0")
  
  Debug "shl64(x,4)"
  x = %1001
  Debug RSet(Bin(x), 64, "0")
  x = shl64(x, 4)
  Debug RSet(Bin(x), 64, "0")
  
  Debug "shr64(x,4)"
  x = %1001
  Debug RSet(Bin(x), 64, "0")
  x = shr64(x, 4)
  Debug RSet(Bin(x), 64, "0")
  
  Debug "rol64(x,29)"
  x = %1001
  Debug RSet(Bin(x), 64, "0")
  x = rol64(x, 29)
  Debug RSet(Bin(x), 64, "0")
  
  Debug "ror64(x,5)"
  x = %1001
  Debug RSet(Bin(x), 64, "0")
  x = ror64(x, 5)
  Debug RSet(Bin(x), 64, "0")
  
  Debug "shl64(-33,4)"
  x = -33
  Debug RSet(Bin(x), 64, "0")
  x = shl64(x, 4)
  Debug RSet(Bin(x), 64, "0")
  
  Debug "shr64(-33,4)"
  x = -33
  Debug RSet(Bin(x), 64, "0")
  x = shr64(x, 4)
  Debug RSet(Bin(x), 64, "0")
  
  Debug "rol64(-33,50)"
  x = -33
  Debug RSet(Bin(x), 64, "0")
  x = rol64(x, 50)
  Debug RSet(Bin(x), 64, "0")
  
  Debug "ror64(-33,8)"
  x = -33
  Debug RSet(Bin(x), 64, "0")
  x = ror64(x, 8)
  Debug RSet(Bin(x), 64, "0")
  
  Debug "SetBit"
  a.q = 0
  b.q = 15
  c1.q = SetBit32(a, b)
  c2.q = SetBit64(a, b)
  c1.q = GetBit32(c1,b)
  c2.q = GetBit64(c2,b)
  Debug c1
  Debug c2
  
  Debug "ClrBit"
  c1 = ClrBit32(a, b)
  c2 = ClrBit64(a, b)
  c1 = GetBit32(c1,b)
  c2 = GetBit64(c2,b)
  Debug c1
  Debug c2
  
  Debug "ToggleBit"
  c1 = 1 << 63
  c2 = ToggleBit64(c1, 1)
  Debug Hex(c2)
CompilerEndIf
Last edited by mk-soft on Thu Feb 01, 2018 11:19 pm, edited 4 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
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: Bitshift and Rotation

Post by Mistrel »

I recently implemented a lot of these things recently using shifts, ORs, and ANDs. I didn't realize there was assembly for flips and circular shifts. But in retrospect it seems obvious that they would exist.

Always learning new things. Thanks for sharing. :)
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Bitshift and Rotation

Post by davido »

@mk-soft ,

Rather nice.
Definitely comprehensive!

Thank you for sharing. :D
DE AA EB
User avatar
Michael Vogel
Addict
Addict
Posts: 2797
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Bitshift and Rotation

Post by Michael Vogel »

Hm, does ROR64 work correctly? It returns 0 here for your example ROR64(17,5)...

Code: Select all

; ***************************************************************************************
; Kommentar:	Bitshift and Rotation
; Author:		mk-soft
; Second Author:	
; Datei:			Bitshift.pb
; Version:		v1.02
; Erstellt:		09.06.2007
; Geändert:		04.11.2016
; ***************************************************************************************

Procedure ROL32(value.l, count.l = 1); 	Bitshift left rotation

	!mov eax, dword [p.v_value]
	!mov ecx, dword [p.v_count]
	!rol eax, cl
	ProcedureReturn

EndProcedure
Procedure ROR32(value.l, count.l = 1); 	Bitshift right rotation

	!mov eax, dword [p.v_value]
	!mov ecx, dword [p.v_count]
	!ror eax, cl
	ProcedureReturn

EndProcedure
Procedure.q ROL64(value.q, count.q = 1);	Bitshift left rotation

	CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
		!mov rax, qword [p.v_value]
		!mov rcx, qword [p.v_count]
		!rol rax, cl
		ProcedureReturn

	CompilerElse
		ProcedureReturn value<<count | value>>(64-count)

	CompilerEndIf

EndProcedure
Procedure.q ROR64(value.q, count.q = 1);	Bitshift right rotation

	CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
		!mov rax, qword [p.v_value]
		!mov rcx, qword [p.v_count]
		!ror rax, cl

	CompilerElse
		ProcedureReturn value>>count | value<<(64-count)

	CompilerEndIf

EndProcedure
Procedure SHL8(value.b, count.l = 1);  	Bitshift left shift

	!xor eax, eax
	!mov al, byte [p.v_value]
	!mov ecx, dword [p.v_count]
	!shl al, cl
	ProcedureReturn

EndProcedure
Procedure SHR8(value.b, count.l = 1);  	Bitshift right shift

	!xor eax, eax
	!mov al, byte [p.v_value]
	!mov ecx, dword [p.v_count]
	!shr al, cl
	ProcedureReturn

EndProcedure
Procedure SHL16(value.w, count.l = 1); 	Bitshift left shift

	!xor eax, eax
	!mov ax, word [p.v_value]
	!mov ecx, dword [p.v_count]
	!shl ax, cl
	ProcedureReturn

EndProcedure
Procedure SHR16(value.w, count.l = 1);	Bitshift right shift

	!xor eax, eax
	!mov ax, word [p.v_value]
	!mov ecx, dword [p.v_count]
	!shr ax, cl
	ProcedureReturn

EndProcedure
Procedure SHL32(value.l, count.l = 1); 	Bitshift left shift

	!mov eax, dword [p.v_value]
	!mov ecx, dword [p.v_count]
	!shl eax, cl
	ProcedureReturn

EndProcedure
Procedure SHR32(value.l, count.l = 1); 	Bitshift right shift

	!mov eax, dword [p.v_value]
	!mov ecx, dword [p.v_count]
	!shr eax, cl
	ProcedureReturn

EndProcedure
Procedure SHL64(value.q, count.q = 1);	Bitshift left shift

	CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
		!mov rax, qword [p.v_value]
		!mov rcx, qword [p.v_count]
		!shl rax, cl
		ProcedureReturn
		
	CompilerElse
		ProcedureReturn value<<count

	CompilerEndIf

EndProcedure
Procedure SHR64(value.q, count.q = 1);	Bitshift right shift

	CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
		!mov rax, qword [p.v_value]
		!mov rcx, qword [p.v_count]
		!shr rax, cl
		ProcedureReturn
		
	CompilerElse
		ProcedureReturn value>>count

	CompilerEndIf

EndProcedure
Procedure.w BSWAP16(value.w)
	
	!xor eax,eax
	!mov ax, word [p.v_value]
	!rol ax, 8
	ProcedureReturn
	
EndProcedure
Procedure BSWAP32(value.l)
	
	!mov eax, dword [p.v_value]
	!bswap eax
	ProcedureReturn
	
EndProcedure
Procedure BSWAP64(value.q)

	CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
		!mov rax, qword [p.v_value]
		!bswap rax
		ProcedureReturn
		
				
	CompilerElse
		ProcedureReturn value>>32 | value<<32


	CompilerEndIf

EndProcedure

; -------------------------------------------------------------------------------------

Macro SignB(Value)
	(Bool(Value > 0) - Bool(Value >> 7))
EndMacro
Macro SignW(Value)
	(Bool(Value > 0) - Bool(Value >> 15))
EndMacro
Macro SignL(Value)
	(Bool(Value > 0) - Bool(Value >> 31))
EndMacro
Macro SignQ(Value)
	(Bool(Value > 0) - Bool(Value >> 63))
EndMacro

; ***************************************************************************************

CompilerIf #PB_Compiler_IsMainFile

	;CompilerIf #PB_Compiler_Processor=#PB_Processor_x86
		x.q
	;CompilerEndIf

	x = $80
	x = shr8(x,2)
	Debug RSet(Bin(x),8,"0")

	x = $02
	x = shl8(x,2)
	Debug RSet(Bin(x),8,"0")

	x = $01020304
	x = bswap32(x)
	Debug RSet(Hex(x),8,"0")

	x = $0102
	x = bswap16(x)
	Debug RSet(Hex(x),8,"0")


	x = %1001
	x = shl32(x, 4)
	Debug Bin(x)

	x = %1001
	x = shr32(x, 4)
	Debug Bin(x)

	x = %1001
	x = rol32(x, 29)
	Debug Bin(x)

	x = %1001
	x = ror32(x, 5)
	Debug Bin(x)

	x = %1001
	x = shl64(x, 4)
	Debug Bin(x)

	x = %1001
	x = shr64(x, 4)
	Debug Bin(x)

	x = %1001
	x = rol64(x, 29)
	Debug Bin(x)

	x = %1001
	x = ror64(x, 5)
	Debug Bin(x)

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

Re: Bitshift and Rotation

Post by mk-soft »

@Michael Vogel

you forget type quad for the procedure...

New update v1.03 :wink:
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
Michael Vogel
Addict
Addict
Posts: 2797
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Bitshift and Rotation

Post by Michael Vogel »

mk-soft wrote:@Michael Vogel

you forget type quad for the procedure...

New update v1.03 :wink:
No, but ProcedureReturn was missing :wink:
Thanks for the update.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Bitshift and Rotation

Post by wilbert »

BSWAP64 for 32 bit is also easy using asm.

Code: Select all

Procedure.q BSWAP64(value.q)
  
  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
  
EndProcedure
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
mk-soft
Always Here
Always Here
Posts: 6207
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Bitshift and Rotation

Post by mk-soft »

Thanks Wilbert

Update code...
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
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Bitshift and Rotation

Post by djes »

Nice and useful ! Maybe you could also add bit test, set and clear (BT, BTS asm instructions and so on) so everybody could manipulate bits directly in PB :)
User avatar
mk-soft
Always Here
Always Here
Posts: 6207
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Bitshift and Rotation

Post by mk-soft »

Now added bit functions... :wink:

The code for 32bit compilers at time not optimize :(
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
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Bitshift and Rotation

Post by djes »

Great, thank you !
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Bitshift and Rotation

Post by luis »

I missed this post, very useful, thank you. :)
"Have you tried turning it off and on again ?"
A little PureBasic review
Post Reply