user manual

90 Efficient 64-Bit Integer Arithmetic
AMD Athlonâ„¢ Processor x86 Code Optimization
22007E/0—November 1999
$r_two_divs:
MOV ECX, EAX ;save dividend_lo in ECX
MOV EAX, EDX ;get dividend_hi
XOR EDX, EDX ;zero extend it into EDX:EAX
DIV EBX ;EAX = quotient_hi, EDX = intermediate
; remainder
MOV EAX, ECX ;EAX = dividend_lo
DIV EBX ;EAX = quotient_lo
MOV EAX, EDX ;EAX = remainder_lo
XOR EDX, EDX ;EDX = remainder_hi = 0
POP EBX ;restore EBX as per calling convention
RET ;done, return to caller
$r_big_divisor:
PUSH EDI ;save EDI as per calling convention
MOV EDI, ECX ;save divisor_hi
SHR EDX, 1 ;shift both divisor and dividend right
RCR EAX, 1 ; by 1 bit
ROR EDI, 1
RCR EBX, 1
BSR ECX, ECX ;ECX = number of remaining shifts
SHRD EBX, EDI, CL ;scale down divisor and dividend such
SHRD EAX, EDX, CL ; that divisor is less than 2^32
SHR EDX, CL ; (i.e. fits in EBX)
ROL EDI, 1 ;restore original divisor (EDI:ESI)
DIV EBX ;compute quotient
MOV EBX, [ESP+12] ;dividend lo-word
MOV ECX, EAX ;save quotient
IMUL EDI, EAX ;quotient * divisor hi-word (low only)
MUL DWORD PTR [ESP+20] ;quotient * divisor lo-word
ADD EDX, EDI ;EDX:EAX = quotient * divisor
SUB EBX, EAX ;dividend_lo – (quot.*divisor)–lo
MOV ECX, [ESP+16] ;dividend_hi
MOV EAX, [ESP+20] ;divisor_lo
SBB ECX, EDX ;subtract divisor * quot. from
; dividend
SBB EDX, EDX ;(remainder < 0)? 0xFFFFFFFF : 0
AND EAX, EDX ;(remainder < 0)? divisor_lo : 0
AND EDX, [ESP+24] ;(remainder < 0)? divisor_hi : 0
ADD EAX, EBX ;remainder += (remainder < 0)?
ADC EDX, ECX ; divisor : 0
POP EDI ;restore EDI as per calling convention
POP EBX ;restore EBX as per calling convention
RET ;done, return to caller
_ullrem ENDP