Mercurial > projects > ldc
diff druntime/src/compiler/dmd/llmath.d @ 759:d3eb054172f9
Added copy of druntime from DMD 2.020 modified for LDC.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:52:37 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/druntime/src/compiler/dmd/llmath.d Tue Nov 11 01:52:37 2008 +0100 @@ -0,0 +1,295 @@ +// llmath.d +// Copyright (C) 1993-2003 by Digital Mars, www.digitalmars.com +// All Rights Reserved +// Written by Walter Bright + +module rt.llmath; + +// 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 ; + cdq ; // [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 ; + } +} + +// Same as __U64_LDBL, but return result as double in [EDX,EAX] +ulong __ULLNGDBL() +{ + asm + { naked ; + call __U64_LDBL ; + sub ESP,8 ; + fstp double ptr [ESP] ; + pop EAX ; + pop EDX ; + 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 ; + } +}