Skip to content

Instantly share code, notes, and snippets.

@qtxie
Last active March 26, 2020 17:43
Show Gist options
  • Save qtxie/f69b60e6011d02e49405fd6590f88640 to your computer and use it in GitHub Desktop.
Save qtxie/f69b60e6011d02e49405fd6590f88640 to your computer and use it in GitHub Desktop.
Red/System []
int64!: alias struct! [
low [integer!]
high [integer!]
]
sub64: func [ ;-- result: a - b
a [int64! value]
b [int64! value]
result [int64!]
][
;-- mov eax, DWORD PTR [ebp+8]
;-- mov edx, DWORD PTR [ebp+12]
;-- sub eax, DWORD PTR [ebp+16]
;-- sbb edx, DWORD PTR [ebp+20]
;-- mov ecx, DWORD PTR [ebp+24]
;-- mov DWORD PTR [ecx], eax
;-- mov DWORD PTR [ecx+4], edx
#inline #{8B45088B550C2B45101B55148B4D188901895104}
]
add64: func [
a [int64! value]
b [int64! value]
result [int64!]
][
;-- mov eax, DWORD PTR [ebp+16]
;-- mov edx, DWORD PTR [ebp+20]
;-- add eax, DWORD PTR [ebp+8]
;-- adc edx, DWORD PTR [ebp+12]
;-- mov ecx, DWORD PTR [ebp+24]
;-- mov DWORD PTR [ecx], eax
;-- mov DWORD PTR [ecx+4], edx
#inline #{8B45108B551403450813550C8B4D188901895104}
]
mul64: func [
a [int64! value]
b [int64! value]
result [int64!]
][
;-- push ebx
;-- mov eax, DWORD PTR [ebp+8]
;-- mov edx, DWORD PTR [ebp+16]
;-- mov ecx, edx
;-- imul ecx, DWORD PTR [ebp+12]
;-- mov ebx, eax
;-- imul ebx, DWORD PTR [ebp+20]
;-- add ecx, ebx
;-- mul edx
;-- add edx, ecx
;-- mov ecx, DWORD PTR [ebp+24]
;-- mov DWORD PTR [ecx], eax
;-- mov DWORD PTR [ecx+4], edx
;-- pop ebx
#inline #{538B45088B551089D10FAF4D0C89C30FAF5D1401D9F7E201CA8B4D1889018951045B}
]
div64: func [
a [int64! value]
b [int64! value]
result [int64!]
][
;; [ebp + 8] stack address of dividend (a)
;; [ebp + 16] stack address of divisor (b)
; push edi
; push esi
; push ebx
;; Determine sign of the result (edi = 0 if result is positive, non-zero
;; otherwise) and make operands positive.
; xor edi,edi ; result sign assumed positive
; mov eax, dword ptr [ebp + 12] ; hi word of a
; or eax,eax ; test to see if signed
; jge short L1 ; skip rest if a is already positive
; inc edi ; complement result sign flag
; mov edx,dword ptr [ebp + 8] ; lo word of a
; neg eax ; make a positive
; neg edx
; sbb eax,0
; mov dword ptr [ebp + 12],eax ; save positive value
; mov dword ptr [ebp + 8],edx
;L1:
; mov eax,dword ptr [ebp + 20] ; hi word of b
; or eax,eax ; test to see if signed
; jge short L2 ; skip rest if b is already positive
; inc edi ; complement the result sign flag
; mov edx,dword ptr [ebp + 16] ; lo word of b
; neg eax ; make b positive
; neg edx
; sbb eax,0
; mov dword ptr [ebp + 20],eax ; save positive value
; mov dword ptr [ebp + 16],edx
;L2:
;;
;; Now do the divide. First look to see if the divisor is less than 4194304K.
;; If so, then we can use a simple algorithm with word divides, otherwise
;; things get a little more complex.
;;
;; NOTE - eax currently contains the high order word of DVSR
;;
; or eax,eax ; check to see if divisor < 4194304K
; jnz short L3 ; nope, gotta do this the hard way
; mov ecx,dword ptr [ebp + 16] ; load divisor
; mov eax,dword ptr [ebp + 12] ; load high word of dividend
; xor edx,edx
; div ecx ; eax <- high order bits of quotient
; mov ebx,eax ; save high bits of quotient
; mov eax,dword ptr [ebp + 8] ; edx:eax <- remainder:lo word of dividend
; div ecx ; eax <- low order bits of quotient
; mov edx,ebx ; edx:eax <- quotient
; jmp short L4 ; set sign, restore stack and return
;;
;; Here we do it the hard way. Remember, eax contains the high word of DVSR
;;
;L3:
; mov ebx,eax ; ebx:ecx <- divisor
; mov ecx,dword ptr [ebp + 16]
; mov edx,dword ptr [ebp + 12] ; edx:eax <- dividend
; mov eax,dword ptr [ebp + 8]
;L5:
; shr ebx,1 ; shift divisor right one bit
; rcr ecx,1
; shr edx,1 ; shift dividend right one bit
; rcr eax,1
; or ebx,ebx
; jnz short L5 ; loop until divisor < 4194304K
; div ecx ; now divide, ignore remainder
; mov esi,eax ; save quotient
;;
;; We may be off by one, so to check, we will multiply the quotient
;; by the divisor and check the result against the orignal dividend
;; Note that we must also check for overflow, which can occur if the
;; dividend is close to 2**64 and the quotient is off by 1.
;;
; mul dword ptr [ebp + 20] ; QUOT * dword ptr [ebp + 20]
; mov ecx,eax
; mov eax,dword ptr [ebp + 16]
; mul esi ; QUOT * dword ptr [ebp + 16]
; add edx,ecx ; EDX:EAX = QUOT * DVSR
; jc short L6 ; carry means Quotient is off by 1
;;
;; do long compare here between original dividend and the result of the
;; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
;; subtract one (1) from the quotient.
;;
; cmp edx,dword ptr [ebp + 12] ; compare hi words of result and original
; ja short L6 ; if result > original, do subtract
; jb short L7 ; if result < original, we are ok
; cmp eax,dword ptr [ebp + 8] ; hi words are equal, compare lo words
; jbe short L7 ; if less or equal we are ok, else subtract
;L6:
; dec esi ; subtract 1 from quotient
;L7:
; xor edx,edx ; edx:eax <- quotient
; mov eax,esi
;;
;; Just the cleanup left to do. edx:eax contains the quotient. Set the sign
;; according to the save value, cleanup the stack, and return.
;;
;L4:
; dec edi ; check to see if result is negative
; jnz short L8 ; if EDI == 0, result should be negative
; neg edx ; otherwise, negate the result
; neg eax
; sbb edx,0
;;
;; Restore the saved registers and return.
;;
;L8:
; pop ebx
; pop esi
; pop edi
;; Save result.
; mov ecx, DWORD PTR [ebp+24]
; mov DWORD PTR [ecx], eax
; mov DWORD PTR [ecx+4], edx
#inline #{57565331FF8B450C09C07D11478B5508F7D8F7DA83D80089450C8955088B451409C07D11478B5510F7D8F7DA83D80089451489551009C075158B4D108B450C31D2F7F189C38B4508F7F189DAEB3A89C38B4D108B550C8B4508D1EBD1D9D1EAD1D809DB75F4F7F189C6F7651489C18B4510F7E601CA720C3B550C770772063B450876014E31D289F04F7507F7DAF7D883DA005B5E5F8B4D188901895104}
]
equal64?: func [
a [int64!]
b [int64!]
return: [logic!]
][
all [
a/low = b/low
a/high = b/high
]
]
rdtsc: func [n [int64!]][
;-- rdtsc
;-- cdq
;-- mov ecx, DWORD PTR [ebp+8]
;-- mov DWORD PTR [ecx], eax
;-- mov DWORD PTR [ecx+4], edx
#inline #{0F31998B4D088901895104}
]
test: func [
/local
f [float!]
n [integer!]
t1 [int64! value]
t2 [int64! value]
t3 [int64! value]
t4 [int64! value]
][
rdtsc :t1
n: 0
loop 100000 [n: n + 1]
rdtsc :t2
sub64 t2 t1 :t3
probe [as int-ptr! t1/high as int-ptr! t1/low]
probe [as int-ptr! t2/high as int-ptr! t2/low]
probe [as int-ptr! t3/high as int-ptr! t3/low]
rdtsc :t1
f: 0.0
loop 100000 [f: f + 1.0]
rdtsc :t2
sub64 t2 t1 :t3
probe 2
probe [as int-ptr! t1/high as int-ptr! t1/low]
probe [as int-ptr! t2/high as int-ptr! t2/low]
probe [as int-ptr! t3/high as int-ptr! t3/low]
add64 t3 t1 :t4
probe 3
probe [as int-ptr! t1/high as int-ptr! t1/low]
probe [as int-ptr! t3/high as int-ptr! t3/low]
probe [as int-ptr! t4/high as int-ptr! t4/low]
probe equal64? :t2 :t4
probe [as int-ptr! t1/high as int-ptr! t1/low]
probe [as int-ptr! t2/high as int-ptr! t2/low]
probe [as int-ptr! t3/high as int-ptr! t3/low]
t1/low: 3
t1/high: 1
t2/low: 2
t2/high: 0
mul64 t1 t2 :t3
probe [as int-ptr! t3/high as int-ptr! t3/low]
t1/low: 3
t1/high: 1
t2/low: 2
t2/high: 0
div64 t1 t2 :t3
probe [as int-ptr! t3/high as int-ptr! t3/low]
]
test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment