windows-nt/Source/XPSP1/NT/windows/richedit/lssrc/zqfromza.c
2020-09-26 16:20:57 +08:00

317 lines
8 KiB
C

#include <limits.h>
#include "lsidefs.h"
#include "zqfromza.h"
#ifdef _X86_
/* =========================================================== */
/* */
/* Functions implemented on Intel X86 Assember */
/* */
/* =========================================================== */
#define HIWORD(x) DWORD PTR [x+4]
#define LOWORD(x) DWORD PTR [x]
long ZqFromZa_Asm (long dzqInch, long za)
{
long result;
__asm
{
mov eax, za;
cmp eax, 0
jge POSITIVE
neg eax
mul dzqInch;
add eax, czaUnitInch / 2
mov ecx, czaUnitInch
adc edx, 0
div ecx;
neg eax
jmp RETURN
POSITIVE:
mul dzqInch;
add eax, czaUnitInch / 2
mov ecx, czaUnitInch
adc edx, 0
div ecx;
RETURN:
mov result, eax
};
/*
Assert (result == ZqFromZa_C (dzqInch, za));
*/
return result;
}
/* D I V 6 4 _ A S M */
/*----------------------------------------------------------------------------
%%Function: Div64_Asm
%%Contact: antons
Intel assembler implementation of 64-bit division. The
orignal code was taken from lldiv.asm (VC++ 6.0).
----------------------------------------------------------------------------*/
__int64 Div64_Asm (__int64 DVND, __int64 DVSR)
{
__int64 result;
__asm {
xor edi,edi // result sign assumed positive
mov eax,HIWORD(DVND) // hi word of a
or eax,eax // test to see if signed
jge L1 // skip rest if a is already positive
inc edi // complement result sign flag
mov edx,LOWORD(DVND) // lo word of a
neg eax // make a positive
neg edx
sbb eax,0
mov HIWORD(DVND),eax // save positive value
mov LOWORD(DVND),edx
L1:
mov eax,HIWORD(DVSR) // hi word of b
or eax,eax // test to see if signed
jge L2 // skip rest if b is already positive
inc edi // complement the result sign flag
mov edx,LOWORD(DVSR) // lo word of a
neg eax // make b positive
neg edx
sbb eax,0
mov HIWORD(DVSR),eax // save positive value
mov LOWORD(DVSR),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 L3 // nope, gotta do this the hard way
mov ecx,LOWORD(DVSR) // load divisor
mov eax,HIWORD(DVND) // 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,LOWORD(DVND) // edx:eax <- remainder:lo word of dividend
div ecx // eax <- low order bits of quotient
mov edx,ebx // edx:eax <- quotient
jmp 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,LOWORD(DVSR)
mov edx,HIWORD(DVND) // edx:eax <- dividend
mov eax,LOWORD(DVND)
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 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 HIWORD(DVSR) // QUOT * HIWORD(DVSR)
mov ecx,eax
mov eax,LOWORD(DVSR)
mul esi // QUOT * LOWORD(DVSR)
add edx,ecx // EDX:EAX = QUOT * DVSR
jc 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,HIWORD(DVND) // compare hi words of result and original
ja L6 // if result > original, do subtract
jb L7 // if result < original, we are ok
cmp eax,LOWORD(DVND) // hi words are equal, compare lo words
jbe 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 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:
mov HIWORD(result),edx
mov LOWORD(result),eax
}; /* ASM */
return result;
}
/* M U L 6 4 _ A S M */
/*----------------------------------------------------------------------------
%%Function: Mul64_Asm
%%Contact: antons
Intel assembler implementation of 64-bit multiplication. The
orignal code was taken from llmul.asm (VC++ 6.0).
----------------------------------------------------------------------------*/
__int64 Mul64_Asm (__int64 A, __int64 B)
{
__int64 result;
__asm {
mov eax,HIWORD(A)
mov ecx,LOWORD(B)
mul ecx // eax has AHI, ecx has BLO, so AHI * BLO
mov esi,eax // save result
mov eax,LOWORD(A)
mul HIWORD(B) // ALO * BHI
add esi,eax // ebx = ((ALO * BHI) + (AHI * BLO))
mov eax,LOWORD(A) // ecx = BLO
mul ecx // so edx:eax = ALO*BLO
add edx,esi // now edx has all the LO*HI stuff
mov HIWORD(result),edx
mov LOWORD(result),eax
}; /* ASM */
return result;
}
/* =========================================================== */
/* */
/* End of Assembler functions */
/* */
/* =========================================================== */
#endif /* _X86_ */
long ZqFromZa_C (long dzqInch, long za)
{
long cInches;
long zaExtra;
if (za < 0)
{
Assert (((long) -za) > 0); /* Check for overflow */
return -ZqFromZa_C (dzqInch, -za);
};
Assert(0 <= za);
Assert(0 < dzqInch && dzqInch < zqLim);
Assert(0 < czaUnitInch);
cInches = za / czaUnitInch;
zaExtra = za % czaUnitInch;
return (cInches * dzqInch) +
((zaExtra * dzqInch) + (czaUnitInch/2)) / czaUnitInch;
}
long ZaFromZq(long dzqInch, long zq)
{
long cInches;
long zqExtra;
if (zq < 0)
return -ZaFromZq(dzqInch, -zq);
Assert(0 <= zq);
Assert(0 < dzqInch && dzqInch < zqLim);
Assert(0 < czaUnitInch);
cInches = zq / dzqInch;
zqExtra = zq % dzqInch;
return (cInches * czaUnitInch) +
((zqExtra * czaUnitInch) + ((unsigned long) dzqInch/2)) / dzqInch;
}
long LsLwMultDivR(long l, long lNumer, long lDenom)
{
__int64 llT;
Assert(lDenom != 0);
if (lDenom == 0) /* this is really sloppy! Don't depend on this! */
return LONG_MAX;
if (l == 0)
return 0;
if (lNumer == lDenom)
return l;
llT = Mul64 (l, lNumer);
if ( (l ^ lNumer ^ lDenom) < 0) /* xor sign bits to give result sign */
llT -= lDenom / 2;
else
llT += lDenom / 2;
if ((__int64)(long)llT == llT) /* Did the multiply fit in 32-bits */
return ( ((long)llT) / lDenom); /* If so, do a 32-bit divide. */
llT = Div64 (llT, lDenom);
if (llT > LONG_MAX)
return LONG_MAX;
else if (llT < LONG_MIN)
return LONG_MIN;
else
return (long) llT;
}