; Version: 1.4 2018/12/27 16:30:00
; Author: oscar (www.autoit.de)
#AutoIt3Wrapper_UseX64=y ; AutoIt 64-Bit-Modus
#include-once
#include <Memory.au3>
If Not @AutoItX64 Then Exit ConsoleWriteError('Error! "BitOperations64.au3" works only in x64-Mode!' & @CRLF)

; Assembler-Code at the End of the Script (created with "AssembleIt2" from andy on www.autoit.de)
; This is the Assembler-Code in binary form
Global $__g_dBitOpASMBin[8] = [ _
		'0x575653554889CE4831C9488B04CE48FFC1488B1CCE4821D848FFC14839D172F15D5B5E5FC3', _ ; BitAND
		'0x575653554889CE4831C9488B04CE48FFC1488B1CCE4809D848FFC14839D172F15D5B5E5FC3', _ ; BitOR
		'0x575653554889CE4831C9488B04CE48FFC1488B1CCE4831D848FFC14839D172F15D5B5E5FC3', _ ; BitXOR
		'0x575653554889C848F7D05D5B5E5FC3', _ ; BitNOT
		'0x575653554889D048D3C05D5B5E5FC3', _ ; BitROL
		'0x575653554889D048D3C85D5B5E5FC3', _ ; BitROR
		'0x575653554889D048D3E05D5B5E5FC3', _ ; BitSHL
		'0x575653554889D048D3E85D5B5E5FC3'] ; BitSHR
; Global array-variables (struct, pointer, memsize)
Global $__g_tBitOpASMCode[8], $__g_pBitOpASMCode[8], $__g_iBitOpMemSize[8]

OnAutoItExitRegister('__BitOp64OnExit')
__BitOp64OnStart()

; Allocate memory for the Assembler-Code
Func __BitOp64OnStart()
	For $i = 0 To UBound($__g_dBitOpASMBin) - 1
		$__g_iBitOpMemSize[$i] = StringLen($__g_dBitOpASMBin[$i]) / 2 - 1
		$__g_pBitOpASMCode[$i] = _MemVirtualAlloc(0, $__g_iBitOpMemSize[$i], $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
		If $__g_pBitOpASMCode[$i] = 0 Then Exit ConsoleWriteError("Error! BitOperations64 - Can't allocate virtual memory!")
		$__g_tBitOpASMCode[$i] = DllStructCreate('byte[' & $__g_iBitOpMemSize[$i] & ']', $__g_pBitOpASMCode[$i])
		DllStructSetData($__g_tBitOpASMCode[$i], 1, $__g_dBitOpASMBin[$i])
	Next
EndFunc   ;==>__BitOp64OnStart

; Release the memory when AutoIt exists
Func __BitOp64OnExit()
	For $i = 0 To UBound($__g_dBitOpASMBin) - 1
		If $__g_pBitOpASMCode[$i] > 0 Then _MemVirtualFree($__g_pBitOpASMCode[$i], $__g_iBitOpMemSize[$i], $MEM_DECOMMIT)
	Next
EndFunc   ;==>__BitOp64OnExit

; A bitwise AND operation for 64-Bit-Numbers
; Up to eight parameters can be used direct in the function call. For more parameters use an array in $iV1.
Func _BitAND64($iV1, $iV2 = 0, $iV3 = 0, $iV4 = 0, $iV5 = 0, $iV6 = 0, $iV7 = 0, $iV8 = 0)
	Local $aUINT64[] = [$iV1, $iV2, $iV3, $iV4, $iV5, $iV6, $iV7, $iV8], $iCount = @NumParams, $tData, $pData
	If IsArray($iV1) Then
		$aUINT64 = $iV1
		$iCount = UBound($aUINT64)
	EndIf
	$tData = DllStructCreate('uint64 value[' & $iCount & '];')
	For $i = 1 To $iCount
		DllStructSetData($tData, 1, $aUINT64[$i - 1], $i)
	Next
	$pData = DllStructGetPtr($tData)
	Local $aRet = DllCallAddress('uint64:cdecl', $__g_pBitOpASMCode[0], 'ptr', $pData, 'uint64', $iCount)
	If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc   ;==>_BitAND64

; A bitwise OR operation for 64-Bit-Numbers
; Up to eight parameters can be used direct in the function call. For more parameters use an array in $iV1.
Func _BitOR64($iV1, $iV2 = 0, $iV3 = 0, $iV4 = 0, $iV5 = 0, $iV6 = 0, $iV7 = 0, $iV8 = 0)
	Local $aUINT64[] = [$iV1, $iV2, $iV3, $iV4, $iV5, $iV6, $iV7, $iV8], $iCount = @NumParams, $tData, $pData
	If IsArray($iV1) Then
		$aUINT64 = $iV1
		$iCount = UBound($aUINT64)
	EndIf
	$tData = DllStructCreate('uint64 value[' & $iCount & '];')
	For $i = 1 To $iCount
		DllStructSetData($tData, 1, $aUINT64[$i - 1], $i)
	Next
	$pData = DllStructGetPtr($tData)
	Local $aRet = DllCallAddress('uint64:cdecl', $__g_pBitOpASMCode[1], 'ptr', $pData, 'uint64', $iCount)
	If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc   ;==>_BitOR64

; A bitwise XOR operation for 64-Bit-Numbers
; Up to eight parameters can be used direct in the function call. For more parameters use an array in $iV1.
Func _BitXOR64($iV1, $iV2 = 0, $iV3 = 0, $iV4 = 0, $iV5 = 0, $iV6 = 0, $iV7 = 0, $iV8 = 0)
	Local $aUINT64[] = [$iV1, $iV2, $iV3, $iV4, $iV5, $iV6, $iV7, $iV8], $iCount = @NumParams, $tData, $pData
	If IsArray($iV1) Then
		$aUINT64 = $iV1
		$iCount = UBound($aUINT64)
	EndIf
	$tData = DllStructCreate('uint64 value[' & $iCount & '];')
	For $i = 1 To $iCount
		DllStructSetData($tData, 1, $aUINT64[$i - 1], $i)
	Next
	$pData = DllStructGetPtr($tData)
	Local $aRet = DllCallAddress('uint64:cdecl', $__g_pBitOpASMCode[2], 'ptr', $pData, 'uint64', $iCount)
	If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc   ;==>_BitXOR64

; A bitwise NOT operation for 64-Bit-Numbers
Func _BitNOT64($iValue1)
	Local $aRet = DllCallAddress('uint64:cdecl', $__g_pBitOpASMCode[3], 'uint64', $iValue1)
	If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc   ;==>_BitNOT64

; A helper-function for "_BitROL64" and "_BitROR64"
; $iRotate = Number of bits to rotate to the right (negative numbers rotate left).
Func _BitRotate64($iValue1, $iRotate = 1)
	Return $iRotate = 0 ? $iValue1 : $iRotate > 0 ? _BitROR64($iValue1, $iRotate) : _BitROL64($iValue1, Abs($iRotate))
EndFunc   ;==>_BitRotate64

; A bitwise BitRotateLeft operation for 64-Bit-Numbers
Func _BitROL64($iValue1, $iRotate)
	Local $aRet = DllCallAddress('uint64:cdecl', $__g_pBitOpASMCode[4], 'uint64', $iRotate, 'uint64', $iValue1)
	If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc   ;==>_BitROL64

; A bitwise BitRotateRight operation for 64-Bit-Numbers
Func _BitROR64($iValue1, $iRotate)
	Local $aRet = DllCallAddress('uint64:cdecl', $__g_pBitOpASMCode[5], 'uint64', $iRotate, 'uint64', $iValue1)
	If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc   ;==>_BitROR64

; A helper-function for "_BitSHL64" and "_BitSHR64"
; $iShift = Number of bits to shift to the right (negative numbers shift left).
Func _BitShift64($iValue1, $iShift = 1)
	Return $iShift = 0 ? $iValue1 : $iShift > 0 ? _BitSHR64($iValue1, $iShift) : _BitSHL64($iValue1, Abs($iShift))
EndFunc   ;==>_BitShift64

; A bitwise BitShiftLeft operation for 64-Bit-Numbers
Func _BitSHL64($iValue1, $iShift)
	Local $aRet = DllCallAddress('uint64:cdecl', $__g_pBitOpASMCode[6], 'uint64', $iShift, 'uint64', $iValue1)
	If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc   ;==>_BitSHL64

; A bitwise BitShiftRight operation for 64-Bit-Numbers
Func _BitSHR64($iValue1, $iShift)
	Local $aRet = DllCallAddress('uint64:cdecl', $__g_pBitOpASMCode[7], 'uint64', $iShift, 'uint64', $iValue1)
	If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc   ;==>_BitSHR64

#Region ASM-Code
#Tidy_Off
#cs BitAND
    Use64                                                  ; Assembler 64-Bit-Modus!
    push rdi                                               ; nichtflüchtige Register retten
    push rsi
    push rbx
    push rbp
    mov rsi,rcx                                            ; Buffer (Pointer nach rsi)
    xor rcx,rcx                                            ; Counter auf 0
    mov rax,qword[rsi+rcx*8]                               ; 1. Wert nach rax
	inc rcx                                                ; Counter++
	@loop:
		mov rbx,qword[rsi+rcx*8]                           ; naechsten Wert nach rbx
		and rax,rbx                                        ; rax AND rbx, Ergebnis in rax
		inc rcx                                            ; Counter++
		cmp rcx,rdx                                        ; Vergleich Counter mit Anzahl
		jb @loop                                           ; wenn kleiner, dann Schleife @loop weiter ausfuehren
    pop rbp
    pop rbx
    pop rsi
    pop rdi
    ret
#ce

#cs BitOR
    Use64                                                  ; Assembler 64-Bit-Modus!
    push rdi                                               ; nichtflüchtige Register retten
    push rsi
    push rbx
    push rbp
    mov rsi,rcx                                            ; Buffer (Pointer nach rsi)
    xor rcx,rcx                                            ; Counter auf 0
    mov rax,qword[rsi+rcx*8]                               ; 1. Wert nach rax
	inc rcx                                                ; Counter++
	@loop:
		mov rbx,qword[rsi+rcx*8]                           ; naechsten Wert nach rbx
		or rax,rbx                                         ; rax OR rbx, Ergebnis in rax
		inc rcx                                            ; Counter++
		cmp rcx,rdx                                        ; Vergleich Counter mit Anzahl
		jb @loop                                           ; wenn kleiner, dann Schleife @loop weiter ausfuehren
    pop rbp
    pop rbx
    pop rsi
    pop rdi
    ret
#ce

#cs BitXOR
    Use64                                                  ; Assembler 64-Bit-Modus!
    push rdi                                               ; nichtflüchtige Register retten
    push rsi
    push rbx
    push rbp
    mov rsi,rcx                                            ; Buffer (Pointer nach rsi)
    xor rcx,rcx                                            ; Counter auf 0
    mov rax,qword[rsi+rcx*8]                               ; 1. Wert nach rax
	inc rcx                                                ; Counter++
	@loop:
		mov rbx,qword[rsi+rcx*8]                           ; naechsten Wert nach rbx
		xor rax,rbx                                        ; rax XOR rbx, Ergebnis in rax
		inc rcx                                            ; Counter++
		cmp rcx,rdx                                        ; Vergleich Counter mit Anzahl
		jb @loop                                           ; wenn kleiner, dann Schleife @loop weiter ausfuehren
    pop rbp
    pop rbx
    pop rsi
    pop rdi
    ret
#ce

#cs BitNOT
    Use64                                                  ; Assembler 64-Bit-Modus!
    push rdi                                               ; nichtflüchtige Register retten
    push rsi
    push rbx
    push rbp
    mov rax,rcx                                            ; startwert
    not rax
    pop rbp
    pop rbx
    pop rsi
    pop rdi
    ret
#ce

#cs BitROL
    Use64                                                  ; Assembler 64-Bit-Modus!
    push rdi                                               ; nichtflüchtige Register retten
    push rsi
    push rbx
    push rbp
    mov rax,rdx                                            ; startwert
    rol rax,cl
    pop rbp
    pop rbx
    pop rsi
    pop rdi
    ret
#ce

#cs BitROR
    Use64                                                  ; Assembler 64-Bit-Modus!
    push rdi                                               ; nichtflüchtige Register retten
    push rsi
    push rbx
    push rbp
    mov rax,rdx                                            ; startwert
    ror rax,cl
    pop rbp
    pop rbx
    pop rsi
    pop rdi
    ret
#ce

#cs BitSHL
    Use64                                                  ; Assembler 64-Bit-Modus!
    push rdi                                               ; nichtflüchtige Register retten
    push rsi
    push rbx
    push rbp
    mov rax,rdx                                            ; startwert
    shl rax,cl
    pop rbp
    pop rbx
    pop rsi
    pop rdi
    ret
#ce

#cs BitSHR
    Use64                                                  ; Assembler 64-Bit-Modus!
    push rdi                                               ; nichtflüchtige Register retten
    push rsi
    push rbx
    push rbp
    mov rax,rdx                                            ; startwert
    shr rax,cl
    pop rbp
    pop rbx
    pop rsi
    pop rdi
    ret
#ce
#Tidy_On
#EndRegion ASM-Code
