Here is a replacement for MulDiv() API. The logic is simple. Take absolute values of all arguments and do MUL and DIV, and later OR in the sign of the result. Only thing to take care of is to return -1 if the arguments may cause #DE (per API).

You may save several bytes if you implement it using Jcc. This is my "Jcc-is-evil" version. :) Optimization gurus may find a better way.



option prologue:none
option epilogue:none
MulDiv PROC STDCALL nNumber:DWORD,\
nNumerator:DWORD,nDenominator:DWORD

push ebx
mov eax,[esp+16] ; nDenominator
mov ebx,eax
cdq
xor eax,edx
sub eax,edx
mov [esp+16],esi
mov esi,eax
mov eax,[esp+8] ; nNumber
xor ebx,eax
mov ecx,[esp+12] ; nNumerator
xor ebx,ecx
cdq
xor eax,edx
sub eax,edx
xchg eax,ecx
cdq
xor eax,edx
sub eax,edx
mul ecx
and ebx,80000000h
; check if DIV below would cause #DE
; (div by 0 or overflow)
mov ecx,esi
sar esi,1
add eax,esi
adc edx,0
cmp edx,ecx
sbb esi,esi
; if #DE is expected,
; make divisor UINT_MAX
not esi
or ecx,esi
div ecx
or ebx,esi
mov ecx,ebx
sar ecx,31
; if MSB(eax) == 1, it cannot
; fit in 32 bit singed integer
; => return -1.
cdq
or edx,ebx
xor eax,ecx
sub eax,ecx
pop ebx
or eax,edx
mov esi,[esp+12]
retn 12

MulDiv ENDP


CDQ at the tail, fixed incorrect sign handling at the end
Posted on 2004-02-08 04:44:57 by Starless
I can't understand why you don't use CDQ on the end? And re-arranging the registers saves a couple instructions and reduces dependancies. The latency of DIV is huge - try moving more non-dependant instructions after DIV. Something like:
        div     ebx

pop ebx
or ecx,esi
pop esi
cdq
or eax,ecx
or eax,edx
retn 12
...there is more - I just read over the code and then started working backwards... ;)
Posted on 2004-02-08 13:04:07 by bitRAKE
Like I said, "Optimization gurus may find a better way." :grin:

Yes, not using CDQ at the end was pretty dumb, I see it now.
Posted on 2004-02-08 15:20:22 by Starless
I like how you maintained the API interface - one little piece at a time and we could replace the whole of it with open source ASM versions. :)

I wasn't aware the API function returned -1 in those cases.
Posted on 2004-02-08 17:15:26 by bitRAKE