f6a1e08218
My i386 code from 893df4b
gave the wrong sign to some 8-byte
remainders. Fix by splitting .dvi8 and .rmi8 so each has its own code
to pick the sign. They and .dvu8 and .rmu8 share a private sub
.divrem8 for unsigned division.
Improve the i386 code by using instructions like _bsr_ and _shrd_.
Change the helpers to yield a quotient in ebx:eax or a remainder in
ecx:edx; this seems more convenient, because _div_ puts its quotient
in eax and remainder in edx.
64 lines
1.6 KiB
ArmAsm
64 lines
1.6 KiB
ArmAsm
.sect .text; .sect .rom; .sect .data; .sect .bss
|
|
.sect .text
|
|
.define .divrem8
|
|
|
|
yl=12
|
|
yh=16
|
|
xl=20
|
|
xh=24
|
|
! This private sub for .dvi8, .dvu8, .rmi8, .rmu8
|
|
! does unsigned division of x = xh:xl by y = yh:yl,
|
|
! yields ebx:eax = quotient, ecx:edx = remainder.
|
|
|
|
.divrem8:
|
|
! Caller must set eax, edx, flag z like so:
|
|
! mov edx,yh(esp)
|
|
! test edx,edx
|
|
! mov eax,xh(esp)
|
|
jnz 1f ! jump if y >= 2**32
|
|
|
|
! y = yl, so x / y = xh:xl / yl = qh:0 + (xl + rh) / yl
|
|
! where qh, rh are quotient, remainder from xh / yl.
|
|
mov ecx,yl(esp)
|
|
xor edx,edx ! edx:eax = xh
|
|
div ecx ! eax = qh, edx = rh
|
|
mov ebx,eax
|
|
mov eax,xl(esp) ! edx:eax = qh:xl
|
|
div ecx ! ebx:eax = qh:ql = quotient
|
|
xor ecx,ecx ! ecx:edx = 0:rl = remainder
|
|
ret
|
|
|
|
1: ! Here y >= 2**32. Find y >> cl in [2**31, 2**32).
|
|
mov ebx,yl(esp) ! edx:ebx = y
|
|
bsr ecx,edx ! scan yh for highest set bit
|
|
incb cl ! cl bits from cl-1 to 0
|
|
shrd ebx,edx,cl ! ebx = y >> cl
|
|
|
|
! Estimate x / y as q = (x / (y >> cl)) >> cl.
|
|
xor edx,edx ! edx:eax = xh
|
|
div ebx ! eax = xh / (y >> cl)
|
|
push eax
|
|
mov eax,xl+4(esp) ! push moved xl to xl+4
|
|
div ebx
|
|
pop edx ! edx:eax = x / (y >> cl)
|
|
shrd eax,edx,cl ! eax = q
|
|
|
|
! Calculate the remainder x - y * q. If the subtraction
|
|
! overflows, then the correct quotient is q - 1, else it is q.
|
|
mov ebx,yh(esp)
|
|
imul ebx,eax ! ebx = yh * q
|
|
push eax
|
|
mul yl+4(esp) ! edx:eax = yl * q
|
|
add ebx,edx ! ebx:eax = y * q
|
|
mov edx,xl+4(esp)
|
|
mov ecx,xh+4(esp)
|
|
sub edx,eax
|
|
sbb ecx,ebx ! ecx:edx = remainder
|
|
pop eax ! eax = q
|
|
jnc 1f ! jump unless subtraction overflowed
|
|
dec eax ! fix quotient
|
|
add edx,yl(esp)
|
|
adc ecx,yh(esp) ! fix remainder
|
|
1: xor ebx,ebx ! ebx:eax = quotient
|
|
ret
|