* FILE: lib/rtl/i386/math.S\r
* PROGRAMER: Alex Ionescu (alex@relsoft.net)\r
* Eric Kohl (ekohl@rz-online.de)\r
- * REVISION HISTORY: 27/07/2005 Created\r
+ *\r
+ * Copyright (C) 2002 Michael Ringgaard.\r
+ * All rights reserved. \r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * \r
+ * 1. Redistributions of source code must retain the above copyright \r
+ * notice, this list of conditions and the following disclaimer. \r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution. \r
+ * 3. Neither the name of the project nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission. \r
+\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \r
+ * SUCH DAMAGE.\r
*/\r
\r
/* GLOBALS ****************************************************************/\r
.globl __aullrem\r
.globl __allmul\r
.globl __alldiv\r
+.globl __aulldvrm\r
+.globl __alldvrm\r
\r
/* FUNCTIONS ***************************************************************/\r
\r
\r
.intel_syntax noprefix\r
\r
+/*\r
+ * This routine is called by MSVC-generated code to convert from floating point\r
+ * to integer representation. The floating point number to be converted is\r
+ * on the top of the floating point stack.\r
+ */\r
__ftol:\r
/* Set up stack frame */\r
push ebp\r
wait\r
mov ax, [ebp-2]\r
or ah, 0xC\r
+ mov [ebp-4], ax\r
fldcw [ebp-4]\r
\r
/* Do the conversion */\r
- fistp qword ptr [ebp-8]\r
+ fistp qword ptr [ebp-12]\r
\r
/* Restore rounding mode */\r
fldcw [ebp-2]\r
/* Remove stack frame and return*/\r
leave\r
ret\r
+\r
+__alldvrm:\r
+ push edi\r
+ push esi\r
+ push ebp\r
+\r
+// Set up the local stack and save the index registers. When this is done\r
+// the stack frame will look as follows (assuming that the expression a/b will\r
+// generate a call to alldvrm(a, b)):\r
+//\r
+// -----------------\r
+// | |\r
+// |---------------|\r
+// | |\r
+// |--divisor (b)--|\r
+// | |\r
+// |---------------|\r
+// | |\r
+// |--dividend (a)-|\r
+// | |\r
+// |---------------|\r
+// | return addr** |\r
+// |---------------|\r
+// | EDI |\r
+// |---------------|\r
+// | ESI |\r
+// |---------------|\r
+// ESP---->| EBP |\r
+// -----------------\r
+//\r
+\r
+#define DVNDLO [esp + 16] // stack address of dividend (a)\r
+#define DVNDHI [esp + 20] // stack address of dividend (a)\r
+#define DVSRLO [esp + 24] // stack address of divisor (b)\r
+#define DVSRHI [esp + 28] // stack address of divisor (b)\r
+\r
+// Determine sign of the quotient (edi = 0 if result is positive, non-zero\r
+// otherwise) and make operands positive.\r
+// Sign of the remainder is kept in ebp.\r
+\r
+ xor edi,edi // result sign assumed positive\r
+ xor ebp,ebp // result sign assumed positive\r
+\r
+ mov eax,DVNDHI // hi word of a\r
+ or eax,eax // test to see if signed\r
+ jge short L1 // skip rest if a is already positive\r
+ inc edi // complement result sign flag\r
+ inc ebp // complement result sign flag\r
+ mov edx,DVNDLO // lo word of a\r
+ neg eax // make a positive\r
+ neg edx\r
+ sbb eax,0\r
+ mov DVNDHI,eax // save positive value\r
+ mov DVNDLO,edx\r
+L1:\r
+ mov eax,DVSRHI // hi word of b\r
+ or eax,eax // test to see if signed\r
+ jge short L2 // skip rest if b is already positive\r
+ inc edi // complement the result sign flag\r
+ mov edx,DVSRLO // lo word of a\r
+ neg eax // make b positive\r
+ neg edx\r
+ sbb eax,0\r
+ mov DVSRHI,eax // save positive value\r
+ mov DVSRLO,edx\r
+L2:\r
+\r
+//\r
+// Now do the divide. First look to see if the divisor is less than 4194304K.\r
+// If so, then we can use a simple algorithm with word divides, otherwise\r
+// things get a little more complex.\r
+//\r
+// NOTE - eax currently contains the high order word of DVSR\r
+//\r
+\r
+ or eax,eax // check to see if divisor < 4194304K\r
+ jnz short L3 // nope, gotta do this the hard way\r
+ mov ecx,DVSRLO // load divisor\r
+ mov eax,DVNDHI // load high word of dividend\r
+ xor edx,edx\r
+ div ecx // eax <- high order bits of quotient\r
+ mov ebx,eax // save high bits of quotient\r
+ mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend\r
+ div ecx // eax <- low order bits of quotient\r
+ mov esi,eax // ebx:esi <- quotient\r
+//\r
+// Now we need to do a multiply so that we can compute the remainder.\r
+//\r
+ mov eax,ebx // set up high word of quotient\r
+ mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR\r
+ mov ecx,eax // save the result in ecx\r
+ mov eax,esi // set up low word of quotient\r
+ mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR\r
+ add edx,ecx // EDX:EAX = QUOT * DVSR\r
+ jmp short L4 // complete remainder calculation\r
+\r
+//\r
+// Here we do it the hard way. Remember, eax contains the high word of DVSR\r
+//\r
+\r
+L3:\r
+ mov ebx,eax // ebx:ecx <- divisor\r
+ mov ecx,DVSRLO\r
+ mov edx,DVNDHI // edx:eax <- dividend\r
+ mov eax,DVNDLO\r
+L5:\r
+ shr ebx,1 // shift divisor right one bit\r
+ rcr ecx,1\r
+ shr edx,1 // shift dividend right one bit\r
+ rcr eax,1\r
+ or ebx,ebx\r
+ jnz short L5 // loop until divisor < 4194304K\r
+ div ecx // now divide, ignore remainder\r
+ mov esi,eax // save quotient\r
+\r
+//\r
+// We may be off by one, so to check, we will multiply the quotient\r
+// by the divisor and check the result against the orignal dividend\r
+// Note that we must also check for overflow, which can occur if the\r
+// dividend is close to 2**64 and the quotient is off by 1.\r
+//\r
+\r
+ mul dword ptr DVSRHI // QUOT * DVSRHI\r
+ mov ecx,eax\r
+ mov eax,DVSRLO\r
+ mul esi // QUOT * DVSRLO\r
+ add edx,ecx // EDX:EAX = QUOT * DVSR\r
+ jc short L6 // carry means Quotient is off by 1\r
+\r
+//\r
+// do long compare here between original dividend and the result of the\r
+// multiply in edx:eax. If original is larger or equal, we are ok, otherwise\r
+// subtract one (1) from the quotient.\r
+//\r
+\r
+ cmp edx,DVNDHI // compare hi words of result and original\r
+ ja short L6 // if result > original, do subtract\r
+ jb short L7 // if result < original, we are ok\r
+ cmp eax,DVNDLO // hi words are equal, compare lo words\r
+ jbe short L7 // if less or equal we are ok, else subtract\r
+L6:\r
+ dec esi // subtract 1 from quotient\r
+ sub eax,DVSRLO // subtract divisor from result\r
+ sbb edx,DVSRHI\r
+L7:\r
+ xor ebx,ebx // ebx:esi <- quotient\r
+\r
+L4:\r
+//\r
+// Calculate remainder by subtracting the result from the original dividend.\r
+// Since the result is already in a register, we will do the subtract in the\r
+// opposite direction and negate the result if necessary.\r
+//\r
+\r
+ sub eax,DVNDLO // subtract dividend from result\r
+ sbb edx,DVNDHI\r
+\r
+//\r
+// Now check the result sign flag to see if the result is supposed to be positive\r
+// or negative. It is currently negated (because we subtracted in the 'wrong'\r
+// direction), so if the sign flag is set we are done, otherwise we must negate\r
+// the result to make it positive again.\r
+//\r
+\r
+ dec ebp // check result sign flag\r
+ jns short L9 // result is ok, set up the quotient\r
+ neg edx // otherwise, negate the result\r
+ neg eax\r
+ sbb edx,0\r
+\r
+//\r
+// Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.\r
+//\r
+L9:\r
+ mov ecx,edx\r
+ mov edx,ebx\r
+ mov ebx,ecx\r
+ mov ecx,eax\r
+ mov eax,esi\r
+\r
+//\r
+// Just the cleanup left to do. edx:eax contains the quotient. Set the sign\r
+// according to the save value, cleanup the stack, and return.\r
+//\r
+\r
+ dec edi // check to see if result is negative\r
+ jnz short L8 // if EDI == 0, result should be negative\r
+ neg edx // otherwise, negate the result\r
+ neg eax\r
+ sbb edx,0\r
+\r
+//\r
+// Restore the saved registers and return.\r
+//\r
+\r
+L8:\r
+ pop ebp\r
+ pop esi\r
+ pop edi\r
+\r
+ ret 16\r
+\r
+__aulldvrm:\r
+\r
+// ulldvrm - unsigned long divide and remainder\r
+//\r
+// Purpose:\r
+// Does a unsigned long divide and remainder of the arguments. Arguments\r
+// are not changed.\r
+//\r
+// Entry:\r
+// Arguments are passed on the stack:\r
+// 1st pushed: divisor (QWORD)\r
+// 2nd pushed: dividend (QWORD)\r
+//\r
+// Exit:\r
+// EDX:EAX contains the quotient (dividend/divisor)\r
+// EBX:ECX contains the remainder (divided % divisor)\r
+// NOTE: this routine removes the parameters from the stack.\r
+//\r
+// Uses:\r
+// ECX\r
+//\r
+ push esi\r
+\r
+// Set up the local stack and save the index registers. When this is done\r
+// the stack frame will look as follows (assuming that the expression a/b will\r
+// generate a call to aulldvrm(a, b)):\r
+//\r
+// -----------------\r
+// | |\r
+// |---------------|\r
+// | |\r
+// |--divisor (b)--|\r
+// | |\r
+// |---------------|\r
+// | |\r
+// |--dividend (a)-|\r
+// | |\r
+// |---------------|\r
+// | return addr** |\r
+// |---------------|\r
+// ESP---->| ESI |\r
+// -----------------\r
+//\r
+\r
+#undef DVNDLO\r
+#undef DVNDHI\r
+#undef DVSRLO\r
+#undef DVSRHI\r
+#define DVNDLO [esp + 8] // stack address of dividend (a)\r
+#define DVNDHI [esp + 8] // stack address of dividend (a)\r
+#define DVSRLO [esp + 16] // stack address of divisor (b)\r
+#define DVSRHI [esp + 20] // stack address of divisor (b)\r
+\r
+//\r
+// Now do the divide. First look to see if the divisor is less than 4194304K.\r
+// If so, then we can use a simple algorithm with word divides, otherwise\r
+// things get a little more complex.\r
+//\r
+\r
+ mov eax,DVSRHI // check to see if divisor < 4194304K\r
+ or eax,eax\r
+ jnz short .L1 // nope, gotta do this the hard way\r
+ mov ecx,DVSRLO // load divisor\r
+ mov eax,DVNDHI // load high word of dividend\r
+ xor edx,edx\r
+ div ecx // get high order bits of quotient\r
+ mov ebx,eax // save high bits of quotient\r
+ mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend\r
+ div ecx // get low order bits of quotient\r
+ mov esi,eax // ebx:esi <- quotient\r
+\r
+//\r
+// Now we need to do a multiply so that we can compute the remainder.\r
+//\r
+ mov eax,ebx // set up high word of quotient\r
+ mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR\r
+ mov ecx,eax // save the result in ecx\r
+ mov eax,esi // set up low word of quotient\r
+ mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR\r
+ add edx,ecx // EDX:EAX = QUOT * DVSR\r
+ jmp short .L2 // complete remainder calculation\r
+\r
+//\r
+// Here we do it the hard way. Remember, eax contains DVSRHI\r
+//\r
+\r
+.L1:\r
+ mov ecx,eax // ecx:ebx <- divisor\r
+ mov ebx,DVSRLO\r
+ mov edx,DVNDHI // edx:eax <- dividend\r
+ mov eax,DVNDLO\r
+.L3:\r
+ shr ecx,1 // shift divisor right one bit// hi bit <- 0\r
+ rcr ebx,1\r
+ shr edx,1 // shift dividend right one bit// hi bit <- 0\r
+ rcr eax,1\r
+ or ecx,ecx\r
+ jnz short .L3 // loop until divisor < 4194304K\r
+ div ebx // now divide, ignore remainder\r
+ mov esi,eax // save quotient\r
+\r
+//\r
+// We may be off by one, so to check, we will multiply the quotient\r
+// by the divisor and check the result against the orignal dividend\r
+// Note that we must also check for overflow, which can occur if the\r
+// dividend is close to 2**64 and the quotient is off by 1.\r
+//\r
+\r
+ mul dword ptr DVSRHI // QUOT * DVSRHI\r
+ mov ecx,eax\r
+ mov eax,DVSRLO\r
+ mul esi // QUOT * DVSRLO\r
+ add edx,ecx // EDX:EAX = QUOT * DVSR\r
+ jc short .L4 // carry means Quotient is off by 1\r
+\r
+//\r
+// do long compare here between original dividend and the result of the\r
+// multiply in edx:eax. If original is larger or equal, we are ok, otherwise\r
+// subtract one (1) from the quotient.\r
+//\r
+\r
+ cmp edx,DVNDHI // compare hi words of result and original\r
+ ja short .L4 // if result > original, do subtract\r
+ jb short .L5 // if result < original, we are ok\r
+ cmp eax,DVNDLO // hi words are equal, compare lo words\r
+ jbe short .L5 // if less or equal we are ok, else subtract\r
+.L4:\r
+ dec esi // subtract 1 from quotient\r
+ sub eax,DVSRLO // subtract divisor from result\r
+ sbb edx,DVSRHI\r
+.L5:\r
+ xor ebx,ebx // ebx:esi <- quotient\r
+\r
+.L2:\r
+//\r
+// Calculate remainder by subtracting the result from the original dividend.\r
+// Since the result is already in a register, we will do the subtract in the\r
+// opposite direction and negate the result.\r
+//\r
+\r
+ sub eax,DVNDLO // subtract dividend from result\r
+ sbb edx,DVNDHI\r
+ neg edx // otherwise, negate the result\r
+ neg eax\r
+ sbb edx,0\r
+\r
+//\r
+// Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.\r
+//\r
+ mov ecx,edx\r
+ mov edx,ebx\r
+ mov ebx,ecx\r
+ mov ecx,eax\r
+ mov eax,esi\r
+//\r
+// Just the cleanup left to do. edx:eax contains the quotient.\r
+// Restore the saved registers and return.\r
+//\r
+\r
+ pop esi\r
+\r
+ ret 16\r
+\r