2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Run-Time Library
5 * FILE: lib/rtl/i386/math.S
6 * PROGRAMER: Alex Ionescu (alex@relsoft.net)
7 * Eric Kohl (ekohl@rz-online.de)
9 * Copyright (C) 2002 Michael Ringgaard.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the project nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 /* GLOBALS ****************************************************************/
52 /* FUNCTIONS ***************************************************************/
56 * __alldiv(long long Dividend, long long Divisor);
59 * [ESP+04h] - long long Dividend
60 * [ESP+0Ch] - long long Divisor
64 * EDX:EAX - long long quotient (Dividend/Divisor)
66 * Routine removes the arguments from the stack.
74 * __allmul(long long Multiplier, long long Multiplicand);
77 * [ESP+04h] - long long Multiplier
78 * [ESP+0Ch] - long long Multiplicand
82 * EDX:EAX - long long product (Multiplier*Multiplicand)
84 * Routine removes the arguments from the stack.
104 leal (%ebx,%esi), %eax
117 * __aullrem(unsigned long long Dividend, unsigned long long Divisor);
120 * [ESP+04h] - unsigned long long Dividend
121 * [ESP+0Ch] - unsigned long long Divisor
125 * EDX:EAX - unsigned long long remainder (Dividend%Divisor)
127 * Routine removes the arguments from the stack.
135 * __allshl(long long Value, unsigned char Shift);
138 * EDX:EAX - signed long long value to be shifted left
139 * CL - number of bits to shift by
143 * EDX:EAX - shifted value
146 shldl %cl, %eax, %edx
157 * __allshr(long long Value, unsigned char Shift);
160 * EDX:EAX - signed long long value to be shifted right
161 * CL - number of bits to shift by
165 * EDX:EAX - shifted value
168 shrdl %cl, %edx, %eax
179 * __aulldiv(unsigned long long Dividend, unsigned long long Divisor);
182 * [ESP+04h] - unsigned long long Dividend
183 * [ESP+0Ch] - unsigned long long Divisor
187 * EDX:EAX - unsigned long long quotient (Dividend/Divisor)
189 * Routine removes the arguments from the stack.
197 * __aullshr(unsigned long long Value, unsigned char Shift);
200 * EDX:EAX - unsigned long long value to be shifted right
201 * CL - number of bits to shift by
205 * EDX:EAX - shifted value
208 shrdl %cl, %edx, %eax
218 * __allrem(long long Dividend, long long Divisor);
221 * [ESP+04h] - long long Dividend
222 * [ESP+0Ch] - long long Divisor
226 * EDX:EAX - long long remainder (Dividend/Divisor)
228 * Routine removes the arguments from the stack.
234 .intel_syntax noprefix
237 * This routine is called by MSVC-generated code to convert from floating point
238 * to integer representation. The floating point number to be converted is
239 * on the top of the floating point stack.
242 /* Set up stack frame */
246 /* Set "round towards zero" mode */
254 /* Do the conversion */
255 fistp qword ptr [ebp-12]
257 /* Restore rounding mode */
264 /* Remove stack frame and return*/
273 // Set up the local stack and save the index registers. When this is done
274 // the stack frame will look as follows (assuming that the expression a/b will
275 // generate a call to alldvrm(a, b)):
298 #define DVNDLO [esp + 16] // stack address of dividend (a)
299 #define DVNDHI [esp + 20] // stack address of dividend (a)
300 #define DVSRLO [esp + 24] // stack address of divisor (b)
301 #define DVSRHI [esp + 28] // stack address of divisor (b)
303 // Determine sign of the quotient (edi = 0 if result is positive, non-zero
304 // otherwise) and make operands positive.
305 // Sign of the remainder is kept in ebp.
307 xor edi,edi // result sign assumed positive
308 xor ebp,ebp // result sign assumed positive
310 mov eax,DVNDHI // hi word of a
311 or eax,eax // test to see if signed
312 jge short L1 // skip rest if a is already positive
313 inc edi // complement result sign flag
314 inc ebp // complement result sign flag
315 mov edx,DVNDLO // lo word of a
316 neg eax // make a positive
319 mov DVNDHI,eax // save positive value
322 mov eax,DVSRHI // hi word of b
323 or eax,eax // test to see if signed
324 jge short L2 // skip rest if b is already positive
325 inc edi // complement the result sign flag
326 mov edx,DVSRLO // lo word of a
327 neg eax // make b positive
330 mov DVSRHI,eax // save positive value
335 // Now do the divide. First look to see if the divisor is less than 4194304K.
336 // If so, then we can use a simple algorithm with word divides, otherwise
337 // things get a little more complex.
339 // NOTE - eax currently contains the high order word of DVSR
342 or eax,eax // check to see if divisor < 4194304K
343 jnz short L3 // nope, gotta do this the hard way
344 mov ecx,DVSRLO // load divisor
345 mov eax,DVNDHI // load high word of dividend
347 div ecx // eax <- high order bits of quotient
348 mov ebx,eax // save high bits of quotient
349 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
350 div ecx // eax <- low order bits of quotient
351 mov esi,eax // ebx:esi <- quotient
353 // Now we need to do a multiply so that we can compute the remainder.
355 mov eax,ebx // set up high word of quotient
356 mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR
357 mov ecx,eax // save the result in ecx
358 mov eax,esi // set up low word of quotient
359 mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR
360 add edx,ecx // EDX:EAX = QUOT * DVSR
361 jmp short L4 // complete remainder calculation
364 // Here we do it the hard way. Remember, eax contains the high word of DVSR
368 mov ebx,eax // ebx:ecx <- divisor
370 mov edx,DVNDHI // edx:eax <- dividend
373 shr ebx,1 // shift divisor right one bit
375 shr edx,1 // shift dividend right one bit
378 jnz short L5 // loop until divisor < 4194304K
379 div ecx // now divide, ignore remainder
380 mov esi,eax // save quotient
383 // We may be off by one, so to check, we will multiply the quotient
384 // by the divisor and check the result against the orignal dividend
385 // Note that we must also check for overflow, which can occur if the
386 // dividend is close to 2**64 and the quotient is off by 1.
389 mul dword ptr DVSRHI // QUOT * DVSRHI
392 mul esi // QUOT * DVSRLO
393 add edx,ecx // EDX:EAX = QUOT * DVSR
394 jc short L6 // carry means Quotient is off by 1
397 // do long compare here between original dividend and the result of the
398 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
399 // subtract one (1) from the quotient.
402 cmp edx,DVNDHI // compare hi words of result and original
403 ja short L6 // if result > original, do subtract
404 jb short L7 // if result < original, we are ok
405 cmp eax,DVNDLO // hi words are equal, compare lo words
406 jbe short L7 // if less or equal we are ok, else subtract
408 dec esi // subtract 1 from quotient
409 sub eax,DVSRLO // subtract divisor from result
412 xor ebx,ebx // ebx:esi <- quotient
416 // Calculate remainder by subtracting the result from the original dividend.
417 // Since the result is already in a register, we will do the subtract in the
418 // opposite direction and negate the result if necessary.
421 sub eax,DVNDLO // subtract dividend from result
425 // Now check the result sign flag to see if the result is supposed to be positive
426 // or negative. It is currently negated (because we subtracted in the 'wrong'
427 // direction), so if the sign flag is set we are done, otherwise we must negate
428 // the result to make it positive again.
431 dec ebp // check result sign flag
432 jns short L9 // result is ok, set up the quotient
433 neg edx // otherwise, negate the result
438 // Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
448 // Just the cleanup left to do. edx:eax contains the quotient. Set the sign
449 // according to the save value, cleanup the stack, and return.
452 dec edi // check to see if result is negative
453 jnz short L8 // if EDI == 0, result should be negative
454 neg edx // otherwise, negate the result
459 // Restore the saved registers and return.
471 // ulldvrm - unsigned long divide and remainder
474 // Does a unsigned long divide and remainder of the arguments. Arguments
478 // Arguments are passed on the stack:
479 // 1st pushed: divisor (QWORD)
480 // 2nd pushed: dividend (QWORD)
483 // EDX:EAX contains the quotient (dividend/divisor)
484 // EBX:ECX contains the remainder (divided % divisor)
485 // NOTE: this routine removes the parameters from the stack.
492 // Set up the local stack and save the index registers. When this is done
493 // the stack frame will look as follows (assuming that the expression a/b will
494 // generate a call to aulldvrm(a, b)):
517 #define DVNDLO [esp + 8] // stack address of dividend (a)
518 #define DVNDHI [esp + 8] // stack address of dividend (a)
519 #define DVSRLO [esp + 16] // stack address of divisor (b)
520 #define DVSRHI [esp + 20] // stack address of divisor (b)
523 // Now do the divide. First look to see if the divisor is less than 4194304K.
524 // If so, then we can use a simple algorithm with word divides, otherwise
525 // things get a little more complex.
528 mov eax,DVSRHI // check to see if divisor < 4194304K
530 jnz short .L1 // nope, gotta do this the hard way
531 mov ecx,DVSRLO // load divisor
532 mov eax,DVNDHI // load high word of dividend
534 div ecx // get high order bits of quotient
535 mov ebx,eax // save high bits of quotient
536 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
537 div ecx // get low order bits of quotient
538 mov esi,eax // ebx:esi <- quotient
541 // Now we need to do a multiply so that we can compute the remainder.
543 mov eax,ebx // set up high word of quotient
544 mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR
545 mov ecx,eax // save the result in ecx
546 mov eax,esi // set up low word of quotient
547 mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR
548 add edx,ecx // EDX:EAX = QUOT * DVSR
549 jmp short .L2 // complete remainder calculation
552 // Here we do it the hard way. Remember, eax contains DVSRHI
556 mov ecx,eax // ecx:ebx <- divisor
558 mov edx,DVNDHI // edx:eax <- dividend
561 shr ecx,1 // shift divisor right one bit// hi bit <- 0
563 shr edx,1 // shift dividend right one bit// hi bit <- 0
566 jnz short .L3 // loop until divisor < 4194304K
567 div ebx // now divide, ignore remainder
568 mov esi,eax // save quotient
571 // We may be off by one, so to check, we will multiply the quotient
572 // by the divisor and check the result against the orignal dividend
573 // Note that we must also check for overflow, which can occur if the
574 // dividend is close to 2**64 and the quotient is off by 1.
577 mul dword ptr DVSRHI // QUOT * DVSRHI
580 mul esi // QUOT * DVSRLO
581 add edx,ecx // EDX:EAX = QUOT * DVSR
582 jc short .L4 // carry means Quotient is off by 1
585 // do long compare here between original dividend and the result of the
586 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
587 // subtract one (1) from the quotient.
590 cmp edx,DVNDHI // compare hi words of result and original
591 ja short .L4 // if result > original, do subtract
592 jb short .L5 // if result < original, we are ok
593 cmp eax,DVNDLO // hi words are equal, compare lo words
594 jbe short .L5 // if less or equal we are ok, else subtract
596 dec esi // subtract 1 from quotient
597 sub eax,DVSRLO // subtract divisor from result
600 xor ebx,ebx // ebx:esi <- quotient
604 // Calculate remainder by subtracting the result from the original dividend.
605 // Since the result is already in a register, we will do the subtract in the
606 // opposite direction and negate the result.
609 sub eax,DVNDLO // subtract dividend from result
611 neg edx // otherwise, negate the result
616 // Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
624 // Just the cleanup left to do. edx:eax contains the quotient.
625 // Restore the saved registers and return.