mirror of
https://github.com/dlang/phobos.git
synced 2025-05-05 01:20:40 +03:00
280 lines
4.7 KiB
D
280 lines
4.7 KiB
D
// llmath.d
|
|
// Copyright (C) 1993-2003 by Digital Mars, www.digitalmars.com
|
|
// All Rights Reserved
|
|
// Written by Walter Bright
|
|
|
|
// Compiler runtime support for 64 bit longs
|
|
|
|
extern (C):
|
|
|
|
|
|
/***************************************
|
|
* Unsigned long divide.
|
|
* Input:
|
|
* [EDX,EAX],[ECX,EBX]
|
|
* Output:
|
|
* [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
|
|
* [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
|
|
* ESI,EDI destroyed
|
|
*/
|
|
|
|
void __ULDIV__()
|
|
{
|
|
asm
|
|
{
|
|
naked ;
|
|
test ECX,ECX ;
|
|
jz uldiv ;
|
|
|
|
push EBP ;
|
|
|
|
// left justify [ECX,EBX] and leave count of shifts + 1 in EBP
|
|
|
|
mov EBP,1 ; // at least 1 shift
|
|
test ECX,ECX ; // left justified?
|
|
js L1 ; // yes
|
|
jnz L2 ;
|
|
add EBP,8 ;
|
|
mov CH,CL ;
|
|
mov CL,BH ;
|
|
mov BH,BL ;
|
|
xor BL,BL ; // [ECX,EBX] <<= 8
|
|
test ECX,ECX ;
|
|
js L1 ;
|
|
even ;
|
|
L2: inc EBP ; // another shift
|
|
shl EBX,1 ;
|
|
rcl ECX,1 ; // [ECX,EBX] <<= 1
|
|
jno L2 ; // not left justified yet
|
|
|
|
L1: mov ESI,ECX ;
|
|
mov EDI,EBX ; // [ESI,EDI] = divisor
|
|
|
|
mov ECX,EDX ;
|
|
mov EBX,EAX ; // [ECX,EBX] = [EDX,EAX]
|
|
xor EAX,EAX ;
|
|
cwd ; // [EDX,EAX] = 0
|
|
even ;
|
|
L4: cmp ESI,ECX ; // is [ECX,EBX] > [ESI,EDI]?
|
|
ja L3 ; // yes
|
|
jb L5 ; // definitely less than
|
|
cmp EDI,EBX ; // check low order word
|
|
ja L3 ;
|
|
L5: sub EBX,EDI ;
|
|
sbb ECX,ESI ; // [ECX,EBX] -= [ESI,EDI]
|
|
stc ; // rotate in a 1
|
|
L3: rcl EAX,1 ;
|
|
rcl EDX,1 ; // [EDX,EAX] = ([EDX,EAX] << 1) + C
|
|
shr ESI,1 ;
|
|
rcr EDI,1 ; // [ESI,EDI] >>= 1
|
|
dec EBP ; // control count
|
|
jne L4 ;
|
|
pop EBP ;
|
|
ret ;
|
|
|
|
div0: mov EAX,-1 ;
|
|
cwd ; // quotient is -1
|
|
// xor ECX,ECX ;
|
|
// mov EBX,ECX ; // remainder is 0 (ECX and EBX already 0)
|
|
pop EBP ;
|
|
ret ;
|
|
|
|
uldiv: test EDX,EDX ;
|
|
jnz D3 ;
|
|
// Both high words are 0, we can use the DIV instruction
|
|
div EBX ;
|
|
mov EBX,EDX ;
|
|
mov EDX,ECX ; // EDX = ECX = 0
|
|
ret ;
|
|
|
|
even ;
|
|
D3: // Divide [EDX,EAX] by EBX
|
|
mov ECX,EAX ;
|
|
mov EAX,EDX ;
|
|
xor EDX,EDX ;
|
|
div EBX ;
|
|
xchg ECX,EAX ;
|
|
div EBX ;
|
|
// ECX,EAX = result
|
|
// EDX = remainder
|
|
mov EBX,EDX ;
|
|
mov EDX,ECX ;
|
|
xor ECX,ECX ;
|
|
ret ;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************
|
|
* Signed long divide.
|
|
* Input:
|
|
* [EDX,EAX],[ECX,EBX]
|
|
* Output:
|
|
* [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
|
|
* [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
|
|
* ESI,EDI destroyed
|
|
*/
|
|
|
|
void __LDIV__()
|
|
{
|
|
asm
|
|
{
|
|
naked ;
|
|
test EDX,EDX ; // [EDX,EAX] negative?
|
|
jns L10 ; // no
|
|
//neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX]
|
|
neg EDX ;
|
|
neg EAX ;
|
|
sbb EDX,0 ;
|
|
test ECX,ECX ; // [ECX,EBX] negative?
|
|
jns L11 ; // no
|
|
//neg64 ECX,EBX ;
|
|
neg ECX ;
|
|
neg EBX ;
|
|
sbb ECX,0 ;
|
|
call __ULDIV__ ;
|
|
//neg64 ECX,EBX ; // remainder same sign as dividend
|
|
neg ECX ;
|
|
neg EBX ;
|
|
sbb ECX,0 ;
|
|
ret ;
|
|
|
|
L11: call __ULDIV__ ;
|
|
//neg64 ECX,EBX ; // remainder same sign as dividend
|
|
neg ECX ;
|
|
neg EBX ;
|
|
sbb ECX,0 ;
|
|
//neg64 EDX,EAX ; // quotient is negative
|
|
neg EDX ;
|
|
neg EAX ;
|
|
sbb EDX,0 ;
|
|
ret ;
|
|
|
|
L10: test ECX,ECX ; // [ECX,EBX] negative?
|
|
jns L12 ; // no (all is positive)
|
|
//neg64 ECX,EBX ;
|
|
neg ECX ;
|
|
neg EBX ;
|
|
sbb ECX,0 ;
|
|
call __ULDIV__ ;
|
|
//neg64 EDX,EAX ; // quotient is negative
|
|
neg EDX ;
|
|
neg EAX ;
|
|
sbb EDX,0 ;
|
|
ret ;
|
|
|
|
L12: jmp __ULDIV__ ;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************
|
|
* Compare [EDX,EAX] with [ECX,EBX]
|
|
* Signed
|
|
* Returns result in flags
|
|
*/
|
|
|
|
void __LCMP__()
|
|
{
|
|
asm
|
|
{
|
|
naked ;
|
|
cmp EDX,ECX ;
|
|
jne C1 ;
|
|
push EDX ;
|
|
xor EDX,EDX ;
|
|
cmp EAX,EBX ;
|
|
jz C2 ;
|
|
ja C3 ;
|
|
dec EDX ;
|
|
pop EDX ;
|
|
ret ;
|
|
|
|
C3: inc EDX ;
|
|
C2: pop EDX ;
|
|
C1: ret ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert ulong to real
|
|
|
|
private real adjust = cast(real)0x800_0000_0000_0000 * 0x10;
|
|
|
|
real __U64_LDBL()
|
|
{
|
|
asm
|
|
{ naked ;
|
|
push EDX ;
|
|
push EAX ;
|
|
and dword ptr 4[ESP], 0x7FFFFFFF ;
|
|
fild qword ptr [ESP] ;
|
|
test EDX,EDX ;
|
|
jns L1 ;
|
|
fld real ptr adjust ;
|
|
faddp ST(1), ST ;
|
|
L1: ;
|
|
add ESP, 8 ;
|
|
ret ;
|
|
}
|
|
}
|
|
|
|
|
|
// Convert double to ulong
|
|
|
|
private short roundTo0 = 0xFBF;
|
|
|
|
ulong __DBLULLNG()
|
|
{
|
|
// BUG: should handle NAN's and overflows
|
|
asm
|
|
{ naked ;
|
|
push EDX ;
|
|
push EAX ;
|
|
fld double ptr [ESP] ;
|
|
sub ESP,8 ;
|
|
fld real ptr adjust ;
|
|
fcomp ;
|
|
fstsw AX ;
|
|
fstcw 8[ESP] ;
|
|
fldcw roundTo0 ;
|
|
sahf ;
|
|
jae L1 ;
|
|
fld real ptr adjust ;
|
|
fsubp ST(1), ST ;
|
|
fistp qword ptr [ESP] ;
|
|
pop EAX ;
|
|
pop EDX ;
|
|
fldcw [ESP] ;
|
|
add ESP,8 ;
|
|
add EDX,0x8000_0000 ;
|
|
ret ;
|
|
L1: ;
|
|
fistp qword ptr [ESP] ;
|
|
pop EAX ;
|
|
pop EDX ;
|
|
fldcw [ESP] ;
|
|
add ESP,8 ;
|
|
ret ;
|
|
}
|
|
}
|
|
|
|
// Convert double in ST0 to uint
|
|
|
|
uint __DBLULNG()
|
|
{
|
|
// BUG: should handle NAN's and overflows
|
|
asm
|
|
{ naked ;
|
|
sub ESP,16 ;
|
|
fstcw 8[ESP] ;
|
|
fldcw roundTo0 ;
|
|
fistp qword ptr [ESP] ;
|
|
fldcw 8[ESP] ;
|
|
pop EAX ;
|
|
add ESP,12 ;
|
|
ret ;
|
|
}
|
|
}
|