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 ****************************************************************/
63 /* DATA ********************************************************************/
66 .long 0 // Floating point zero
67 .long 0 // Floating point zero
72 .intel_syntax noprefix
74 /* FUNCTIONS ***************************************************************/
77 // lldiv - signed long divide
80 // Does a signed long divide of the arguments. Arguments are
84 // Arguments are passed on the stack:
85 // 1st pushed: divisor (QWORD)
86 // 2nd pushed: dividend (QWORD)
89 // EDX:EAX contains the quotient (dividend/divisor)
90 // NOTE: this routine removes the parameters from the stack.
102 // Set up the local stack and save the index registers. When this is done
103 // the stack frame will look as follows (assuming that the expression a/b will
104 // generate a call to lldiv(a, b)):
127 #define DVNDLO [esp + 16] // stack address of dividend (a)
128 #define DVNDHI [esp + 20] // stack address of dividend (a)
129 #define DVSRLO [esp + 24] // stack address of divisor (b)
130 #define DVSRHI [esp + 28] // stack address of divisor (b)
132 // Determine sign of the result (edi = 0 if result is positive, non-zero
133 // otherwise) and make operands positive.
135 xor edi,edi // result sign assumed positive
137 mov eax,DVNDHI // hi word of a
138 or eax,eax // test to see if signed
139 jge short L1 // skip rest if a is already positive
140 inc edi // complement result sign flag
141 mov edx,DVNDLO // lo word of a
142 neg eax // make a positive
145 mov DVNDHI,eax // save positive value
148 mov eax,DVSRHI // hi word of b
149 or eax,eax // test to see if signed
150 jge short L2 // skip rest if b is already positive
151 inc edi // complement the result sign flag
152 mov edx,DVSRLO // lo word of a
153 neg eax // make b positive
156 mov DVSRHI,eax // save positive value
161 // Now do the divide. First look to see if the divisor is less than 4194304K.
162 // If so, then we can use a simple algorithm with word divides, otherwise
163 // things get a little more complex.
165 // NOTE - eax currently contains the high order word of DVSR
168 or eax,eax // check to see if divisor < 4194304K
169 jnz short L3 // nope, gotta do this the hard way
170 mov ecx,DVSRLO // load divisor
171 mov eax,DVNDHI // load high word of dividend
173 div ecx // eax <- high order bits of quotient
174 mov ebx,eax // save high bits of quotient
175 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
176 div ecx // eax <- low order bits of quotient
177 mov edx,ebx // edx:eax <- quotient
178 jmp short L4 // set sign, restore stack and return
181 // Here we do it the hard way. Remember, eax contains the high word of DVSR
185 mov ebx,eax // ebx:ecx <- divisor
187 mov edx,DVNDHI // edx:eax <- dividend
190 shr ebx,1 // shift divisor right one bit
192 shr edx,1 // shift dividend right one bit
195 jnz short L5 // loop until divisor < 4194304K
196 div ecx // now divide, ignore remainder
197 mov esi,eax // save quotient
200 // We may be off by one, so to check, we will multiply the quotient
201 // by the divisor and check the result against the orignal dividend
202 // Note that we must also check for overflow, which can occur if the
203 // dividend is close to 2**64 and the quotient is off by 1.
206 mul dword ptr DVSRHI // QUOT * DVSRHI
209 mul esi // QUOT * DVSRLO
210 add edx,ecx // EDX:EAX = QUOT * DVSR
211 jc short L6 // carry means Quotient is off by 1
214 // do long compare here between original dividend and the result of the
215 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
216 // subtract one (1) from the quotient.
219 cmp edx,DVNDHI // compare hi words of result and original
220 ja short L6 // if result > original, do subtract
221 jb short L7 // if result < original, we are ok
222 cmp eax,DVNDLO // hi words are equal, compare lo words
223 jbe short L7 // if less or equal we are ok, else subtract
225 dec esi // subtract 1 from quotient
227 xor edx,edx // edx:eax <- quotient
231 // Just the cleanup left to do. edx:eax contains the quotient. Set the sign
232 // according to the save value, cleanup the stack, and return.
236 dec edi // check to see if result is negative
237 jnz short L8 // if EDI == 0, result should be negative
238 neg edx // otherwise, negate the result
243 // Restore the saved registers and return.
254 // llmul - long multiply routine
257 // Does a long multiply (same for signed/unsigned)
258 // Parameters are not changed.
261 // Parameters are passed on the stack:
262 // 1st pushed: multiplier (QWORD)
263 // 2nd pushed: multiplicand (QWORD)
266 // EDX:EAX - product of multiplier and multiplicand
267 // NOTE: parameters are removed from the stack
275 #define ALO [esp + 4] // stack address of a
276 #define AHI [esp + 8] // stack address of a
277 #define BLO [esp + 12] // stack address of b
278 #define BHI [esp + 16] // stack address of b
281 // AHI, BHI : upper 32 bits of A and B
282 // ALO, BLO : lower 32 bits of A and B
287 // ---------------------
292 or ecx,eax //test for both hiwords zero.
294 jnz short hard //both are zero, just mult ALO and BLO
299 ret 16 // callee restores the stack
304 // must redefine A and B since esp has been altered
306 #define A2LO [esp + 4] // stack address of a
307 #define A2HI [esp + 8] // stack address of a
308 #define B2LO [esp + 12] // stack address of b
309 #define B2HI [esp + 16] // stack address of b
311 mul ecx //eax has AHI, ecx has BLO, so AHI * BLO
312 mov ebx,eax //save result
315 mul dword ptr B2HI //ALO * BHI
316 add ebx,eax //ebx = ((ALO * BHI) + (AHI * BLO))
318 mov eax,A2LO //ecx = BLO
319 mul ecx //so edx:eax = ALO*BLO
320 add edx,ebx //now edx has all the LO*HI stuff
324 ret 16 // callee restores the stack
327 // llrem - signed long remainder
330 // Does a signed long remainder of the arguments. Arguments are
334 // Arguments are passed on the stack:
335 // 1st pushed: divisor (QWORD)
336 // 2nd pushed: dividend (QWORD)
339 // EDX:EAX contains the remainder (dividend%divisor)
340 // NOTE: this routine removes the parameters from the stack.
351 // Set up the local stack and save the index registers. When this is done
352 // the stack frame will look as follows (assuming that the expression a%b will
353 // generate a call to lrem(a, b)):
378 #define DVNDLO [esp + 12] // stack address of dividend (a)
379 #define DVNDHI [esp + 16] // stack address of dividend (a)
380 #define DVSRLO [esp + 20] // stack address of divisor (b)
381 #define DVSRHI [esp + 24] // stack address of divisor (b)
383 // Determine sign of the result (edi = 0 if result is positive, non-zero
384 // otherwise) and make operands positive.
386 xor edi,edi // result sign assumed positive
388 mov eax,DVNDHI // hi word of a
389 or eax,eax // test to see if signed
390 jge short .L1 // skip rest if a is already positive
391 inc edi // complement result sign flag bit
392 mov edx,DVNDLO // lo word of a
393 neg eax // make a positive
396 mov DVNDHI,eax // save positive value
399 mov eax,DVSRHI // hi word of b
400 or eax,eax // test to see if signed
401 jge short .L2 // skip rest if b is already positive
402 mov edx,DVSRLO // lo word of b
403 neg eax // make b positive
406 mov DVSRHI,eax // save positive value
411 // Now do the divide. First look to see if the divisor is less than 4194304K.
412 // If so, then we can use a simple algorithm with word divides, otherwise
413 // things get a little more complex.
415 // NOTE - eax currently contains the high order word of DVSR
418 or eax,eax // check to see if divisor < 4194304K
419 jnz short .L3 // nope, gotta do this the hard way
420 mov ecx,DVSRLO // load divisor
421 mov eax,DVNDHI // load high word of dividend
423 div ecx // edx <- remainder
424 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
425 div ecx // edx <- final remainder
426 mov eax,edx // edx:eax <- remainder
428 dec edi // check result sign flag
429 jns short .L4 // negate result, restore stack and return
430 jmp short .L8 // result sign ok, restore stack and return
433 // Here we do it the hard way. Remember, eax contains the high word of DVSR
437 mov ebx,eax // ebx:ecx <- divisor
439 mov edx,DVNDHI // edx:eax <- dividend
442 shr ebx,1 // shift divisor right one bit
444 shr edx,1 // shift dividend right one bit
447 jnz short .L5 // loop until divisor < 4194304K
448 div ecx // now divide, ignore remainder
451 // We may be off by one, so to check, we will multiply the quotient
452 // by the divisor and check the result against the orignal dividend
453 // Note that we must also check for overflow, which can occur if the
454 // dividend is close to 2**64 and the quotient is off by 1.
457 mov ecx,eax // save a copy of quotient in ECX
459 xchg ecx,eax // save product, get quotient in EAX
461 add edx,ecx // EDX:EAX = QUOT * DVSR
462 jc short .L6 // carry means Quotient is off by 1
465 // do long compare here between original dividend and the result of the
466 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
467 // subtract the original divisor from the result.
470 cmp edx,DVNDHI // compare hi words of result and original
471 ja short .L6 // if result > original, do subtract
472 jb short .L7 // if result < original, we are ok
473 cmp eax,DVNDLO // hi words are equal, compare lo words
474 jbe short .L7 // if less or equal we are ok, else subtract
476 sub eax,DVSRLO // subtract divisor from result
481 // Calculate remainder by subtracting the result from the original dividend.
482 // Since the result is already in a register, we will do the subtract in the
483 // opposite direction and negate the result if necessary.
486 sub eax,DVNDLO // subtract dividend from result
490 // Now check the result sign flag to see if the result is supposed to be positive
491 // or negative. It is currently negated (because we subtracted in the 'wrong'
492 // direction), so if the sign flag is set we are done, otherwise we must negate
493 // the result to make it positive again.
496 dec edi // check result sign flag
497 jns short .L8 // result is ok, restore stack and return
499 neg edx // otherwise, negate the result
504 // Just the cleanup left to do. edx:eax contains the quotient.
505 // Restore the saved registers and return.
515 // llshl - long shift left
518 // Does a Long Shift Left (signed and unsigned are identical)
519 // Shifts a long left any number of bits.
522 // EDX:EAX - long value to be shifted
523 // CL - number of bits to shift by
526 // EDX:EAX - shifted value
535 // Handle shifts of 64 or more bits (all get 0)
541 // Handle shifts of between 0 and 31 bits
550 // Handle shifts of between 32 and 63 bits
560 // return 0 in edx:eax
568 // llshr - long shift right
571 // Does a signed Long Shift Right
572 // Shifts a long right any number of bits.
575 // EDX:EAX - long value to be shifted
576 // CL - number of bits to shift by
579 // EDX:EAX - shifted value
588 // Handle shifts of 64 bits or more (if shifting 64 bits or more, the result
589 // depends only on the high order bit of edx).
595 // Handle shifts of between 0 and 31 bits
604 // Handle shifts of between 32 and 63 bits
614 // Return double precision 0 or -1, depending on the sign of edx
622 // ulldiv - unsigned long divide
625 // Does a unsigned long divide of the arguments. Arguments are
629 // Arguments are passed on the stack:
630 // 1st pushed: divisor (QWORD)
631 // 2nd pushed: dividend (QWORD)
634 // EDX:EAX contains the quotient (dividend/divisor)
635 // NOTE: this routine removes the parameters from the stack.
646 // Set up the local stack and save the index registers. When this is done
647 // the stack frame will look as follows (assuming that the expression a/b will
648 // generate a call to uldiv(a, b)):
673 #define DVNDLO [esp + 12] // stack address of dividend (a)
674 #define DVNDHI [esp + 16] // stack address of dividend (a)
675 #define DVSRLO [esp + 20] // stack address of divisor (b)
676 #define DVSRHI [esp + 24] // stack address of divisor (b)
679 // Now do the divide. First look to see if the divisor is less than 4194304K.
680 // If so, then we can use a simple algorithm with word divides, otherwise
681 // things get a little more complex.
684 mov eax,DVSRHI // check to see if divisor < 4194304K
686 jnz short ..L1 // nope, gotta do this the hard way
687 mov ecx,DVSRLO // load divisor
688 mov eax,DVNDHI // load high word of dividend
690 div ecx // get high order bits of quotient
691 mov ebx,eax // save high bits of quotient
692 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
693 div ecx // get low order bits of quotient
694 mov edx,ebx // edx:eax <- quotient hi:quotient lo
695 jmp short ..L2 // restore stack and return
698 // Here we do it the hard way. Remember, eax contains DVSRHI
702 mov ecx,eax // ecx:ebx <- divisor
704 mov edx,DVNDHI // edx:eax <- dividend
707 shr ecx,1 // shift divisor right one bit// hi bit <- 0
709 shr edx,1 // shift dividend right one bit// hi bit <- 0
712 jnz short ..L3 // loop until divisor < 4194304K
713 div ebx // now divide, ignore remainder
714 mov esi,eax // save quotient
717 // We may be off by one, so to check, we will multiply the quotient
718 // by the divisor and check the result against the orignal dividend
719 // Note that we must also check for overflow, which can occur if the
720 // dividend is close to 2**64 and the quotient is off by 1.
723 mul dword ptr DVSRHI // QUOT * DVSRHI
726 mul esi // QUOT * DVSRLO
727 add edx,ecx // EDX:EAX = QUOT * DVSR
728 jc short ..L4 // carry means Quotient is off by 1
731 // do long compare here between original dividend and the result of the
732 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
733 // subtract one (1) from the quotient.
736 cmp edx,DVNDHI // compare hi words of result and original
737 ja short ..L4 // if result > original, do subtract
738 jb short ..L5 // if result < original, we are ok
739 cmp eax,DVNDLO // hi words are equal, compare lo words
740 jbe short ..L5 // if less or equal we are ok, else subtract
742 dec esi // subtract 1 from quotient
744 xor edx,edx // edx:eax <- quotient
748 // Just the cleanup left to do. edx:eax contains the quotient.
749 // Restore the saved registers and return.
760 // ullshr - long shift right
763 // Does a unsigned Long Shift Right
764 // Shifts a long right any number of bits.
767 // EDX:EAX - long value to be shifted
768 // CL - number of bits to shift by
771 // EDX:EAX - shifted value
780 // Handle shifts of 64 bits or more (if shifting 64 bits or more, the result
781 // depends only on the high order bit of edx).
787 // Handle shifts of between 0 and 31 bits
796 // Handle shifts of between 32 and 63 bits
806 // return 0 in edx:eax
814 // ullrem - unsigned long remainder
817 // Does a unsigned long remainder of the arguments. Arguments are
821 // Arguments are passed on the stack:
822 // 1st pushed: divisor (QWORD)
823 // 2nd pushed: dividend (QWORD)
826 // EDX:EAX contains the remainder (dividend%divisor)
827 // NOTE: this routine removes the parameters from the stack.
837 // Set up the local stack and save the index registers. When this is done
838 // the stack frame will look as follows (assuming that the expression a%b will
839 // generate a call to ullrem(a, b)):
862 #define DVNDLO [esp + 8] // stack address of dividend (a)
863 #define DVNDHI [esp + 8] // stack address of dividend (a)
864 #define DVSRLO [esp + 16] // stack address of divisor (b)
865 #define DVSRHI [esp + 20] // stack address of divisor (b)
867 // Now do the divide. First look to see if the divisor is less than 4194304K.
868 // If so, then we can use a simple algorithm with word divides, otherwise
869 // things get a little more complex.
872 mov eax,DVSRHI // check to see if divisor < 4194304K
874 jnz short ...L1 // nope, gotta do this the hard way
875 mov ecx,DVSRLO // load divisor
876 mov eax,DVNDHI // load high word of dividend
878 div ecx // edx <- remainder, eax <- quotient
879 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
880 div ecx // edx <- final remainder
881 mov eax,edx // edx:eax <- remainder
883 jmp short ...L2 // restore stack and return
886 // Here we do it the hard way. Remember, eax contains DVSRHI
890 mov ecx,eax // ecx:ebx <- divisor
892 mov edx,DVNDHI // edx:eax <- dividend
895 shr ecx,1 // shift divisor right one bit// hi bit <- 0
897 shr edx,1 // shift dividend right one bit// hi bit <- 0
900 jnz short ...L3 // loop until divisor < 4194304K
901 div ebx // now divide, ignore remainder
904 // We may be off by one, so to check, we will multiply the quotient
905 // by the divisor and check the result against the orignal dividend
906 // Note that we must also check for overflow, which can occur if the
907 // dividend is close to 2**64 and the quotient is off by 1.
910 mov ecx,eax // save a copy of quotient in ECX
912 xchg ecx,eax // put partial product in ECX, get quotient in EAX
914 add edx,ecx // EDX:EAX = QUOT * DVSR
915 jc short ...L4 // carry means Quotient is off by 1
918 // do long compare here between original dividend and the result of the
919 // multiply in edx:eax. If original is larger or equal, we're ok, otherwise
920 // subtract the original divisor from the result.
923 cmp edx,DVNDHI // compare hi words of result and original
924 ja short ...L4 // if result > original, do subtract
925 jb short ...L5 // if result < original, we're ok
926 cmp eax,DVNDLO // hi words are equal, compare lo words
927 jbe short ...L5 // if less or equal we're ok, else subtract
929 sub eax,DVSRLO // subtract divisor from result
934 // Calculate remainder by subtracting the result from the original dividend.
935 // Since the result is already in a register, we will perform the subtract in
936 // the opposite direction and negate the result to make it positive.
939 sub eax,DVNDLO // subtract original dividend from result
941 neg edx // and negate it
946 // Just the cleanup left to do. dx:ax contains the remainder.
947 // Restore the saved registers and return.
958 * This routine is called by MSVC-generated code to convert from floating point
959 * to integer representation. The floating point number to be converted is
960 * on the top of the floating point stack.
963 /* Set up stack frame */
967 /* Set "round towards zero" mode */
975 /* Do the conversion */
976 fistp qword ptr [ebp-12]
978 /* Restore rounding mode */
985 /* Remove stack frame and return*/
994 // Set up the local stack and save the index registers. When this is done
995 // the stack frame will look as follows (assuming that the expression a/b will
996 // generate a call to alldvrm(a, b)):
1000 // |---------------|
1002 // |--divisor (b)--|
1004 // |---------------|
1006 // |--dividend (a)-|
1008 // |---------------|
1009 // | return addr** |
1010 // |---------------|
1012 // |---------------|
1014 // |---------------|
1016 // -----------------
1023 #define DVNDLO [esp + 16] // stack address of dividend (a)
1024 #define DVNDHI [esp + 20] // stack address of dividend (a)
1025 #define DVSRLO [esp + 24] // stack address of divisor (b)
1026 #define DVSRHI [esp + 28] // stack address of divisor (b)
1028 // Determine sign of the quotient (edi = 0 if result is positive, non-zero
1029 // otherwise) and make operands positive.
1030 // Sign of the remainder is kept in ebp.
1032 xor edi,edi // result sign assumed positive
1033 xor ebp,ebp // result sign assumed positive
1035 mov eax,DVNDHI // hi word of a
1036 or eax,eax // test to see if signed
1037 jge short ....L1 // skip rest if a is already positive
1038 inc edi // complement result sign flag
1039 inc ebp // complement result sign flag
1040 mov edx,DVNDLO // lo word of a
1041 neg eax // make a positive
1044 mov DVNDHI,eax // save positive value
1047 mov eax,DVSRHI // hi word of b
1048 or eax,eax // test to see if signed
1049 jge short ....L2 // skip rest if b is already positive
1050 inc edi // complement the result sign flag
1051 mov edx,DVSRLO // lo word of a
1052 neg eax // make b positive
1055 mov DVSRHI,eax // save positive value
1060 // Now do the divide. First look to see if the divisor is less than 4194304K.
1061 // If so, then we can use a simple algorithm with word divides, otherwise
1062 // things get a little more complex.
1064 // NOTE - eax currently contains the high order word of DVSR
1067 or eax,eax // check to see if divisor < 4194304K
1068 jnz short ....L3 // nope, gotta do this the hard way
1069 mov ecx,DVSRLO // load divisor
1070 mov eax,DVNDHI // load high word of dividend
1072 div ecx // eax <- high order bits of quotient
1073 mov ebx,eax // save high bits of quotient
1074 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
1075 div ecx // eax <- low order bits of quotient
1076 mov esi,eax // ebx:esi <- quotient
1078 // Now we need to do a multiply so that we can compute the remainder.
1080 mov eax,ebx // set up high word of quotient
1081 mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR
1082 mov ecx,eax // save the result in ecx
1083 mov eax,esi // set up low word of quotient
1084 mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR
1085 add edx,ecx // EDX:EAX = QUOT * DVSR
1086 jmp short ....L4 // complete remainder calculation
1089 // Here we do it the hard way. Remember, eax contains the high word of DVSR
1093 mov ebx,eax // ebx:ecx <- divisor
1095 mov edx,DVNDHI // edx:eax <- dividend
1098 shr ebx,1 // shift divisor right one bit
1100 shr edx,1 // shift dividend right one bit
1103 jnz short ....L5 // loop until divisor < 4194304K
1104 div ecx // now divide, ignore remainder
1105 mov esi,eax // save quotient
1108 // We may be off by one, so to check, we will multiply the quotient
1109 // by the divisor and check the result against the orignal dividend
1110 // Note that we must also check for overflow, which can occur if the
1111 // dividend is close to 2**64 and the quotient is off by 1.
1114 mul dword ptr DVSRHI // QUOT * DVSRHI
1117 mul esi // QUOT * DVSRLO
1118 add edx,ecx // EDX:EAX = QUOT * DVSR
1119 jc short ....L6 // carry means Quotient is off by 1
1122 // do long compare here between original dividend and the result of the
1123 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
1124 // subtract one (1) from the quotient.
1127 cmp edx,DVNDHI // compare hi words of result and original
1128 ja short ....L6 // if result > original, do subtract
1129 jb short ....L7 // if result < original, we are ok
1130 cmp eax,DVNDLO // hi words are equal, compare lo words
1131 jbe short ....L7 // if less or equal we are ok, else subtract
1133 dec esi // subtract 1 from quotient
1134 sub eax,DVSRLO // subtract divisor from result
1137 xor ebx,ebx // ebx:esi <- quotient
1141 // Calculate remainder by subtracting the result from the original dividend.
1142 // Since the result is already in a register, we will do the subtract in the
1143 // opposite direction and negate the result if necessary.
1146 sub eax,DVNDLO // subtract dividend from result
1150 // Now check the result sign flag to see if the result is supposed to be positive
1151 // or negative. It is currently negated (because we subtracted in the 'wrong'
1152 // direction), so if the sign flag is set we are done, otherwise we must negate
1153 // the result to make it positive again.
1156 dec ebp // check result sign flag
1157 jns short ....L9 // result is ok, set up the quotient
1158 neg edx // otherwise, negate the result
1163 // Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
1173 // Just the cleanup left to do. edx:eax contains the quotient. Set the sign
1174 // according to the save value, cleanup the stack, and return.
1177 dec edi // check to see if result is negative
1178 jnz short ....L8 // if EDI == 0, result should be negative
1179 neg edx // otherwise, negate the result
1184 // Restore the saved registers and return.
1196 // ulldvrm - unsigned long divide and remainder
1199 // Does a unsigned long divide and remainder of the arguments. Arguments
1203 // Arguments are passed on the stack:
1204 // 1st pushed: divisor (QWORD)
1205 // 2nd pushed: dividend (QWORD)
1208 // EDX:EAX contains the quotient (dividend/divisor)
1209 // EBX:ECX contains the remainder (divided % divisor)
1210 // NOTE: this routine removes the parameters from the stack.
1217 // Set up the local stack and save the index registers. When this is done
1218 // the stack frame will look as follows (assuming that the expression a/b will
1219 // generate a call to aulldvrm(a, b)):
1221 // -----------------
1223 // |---------------|
1225 // |--divisor (b)--|
1227 // |---------------|
1229 // |--dividend (a)-|
1231 // |---------------|
1232 // | return addr** |
1233 // |---------------|
1235 // -----------------
1242 #define DVNDLO [esp + 8] // stack address of dividend (a)
1243 #define DVNDHI [esp + 8] // stack address of dividend (a)
1244 #define DVSRLO [esp + 16] // stack address of divisor (b)
1245 #define DVSRHI [esp + 20] // stack address of divisor (b)
1248 // Now do the divide. First look to see if the divisor is less than 4194304K.
1249 // If so, then we can use a simple algorithm with word divides, otherwise
1250 // things get a little more complex.
1253 mov eax,DVSRHI // check to see if divisor < 4194304K
1255 jnz short .....L1 // nope, gotta do this the hard way
1256 mov ecx,DVSRLO // load divisor
1257 mov eax,DVNDHI // load high word of dividend
1259 div ecx // get high order bits of quotient
1260 mov ebx,eax // save high bits of quotient
1261 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
1262 div ecx // get low order bits of quotient
1263 mov esi,eax // ebx:esi <- quotient
1266 // Now we need to do a multiply so that we can compute the remainder.
1268 mov eax,ebx // set up high word of quotient
1269 mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR
1270 mov ecx,eax // save the result in ecx
1271 mov eax,esi // set up low word of quotient
1272 mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR
1273 add edx,ecx // EDX:EAX = QUOT * DVSR
1274 jmp short .....L2 // complete remainder calculation
1277 // Here we do it the hard way. Remember, eax contains DVSRHI
1281 mov ecx,eax // ecx:ebx <- divisor
1283 mov edx,DVNDHI // edx:eax <- dividend
1286 shr ecx,1 // shift divisor right one bit// hi bit <- 0
1288 shr edx,1 // shift dividend right one bit// hi bit <- 0
1291 jnz short .....L3 // loop until divisor < 4194304K
1292 div ebx // now divide, ignore remainder
1293 mov esi,eax // save quotient
1296 // We may be off by one, so to check, we will multiply the quotient
1297 // by the divisor and check the result against the orignal dividend
1298 // Note that we must also check for overflow, which can occur if the
1299 // dividend is close to 2**64 and the quotient is off by 1.
1302 mul dword ptr DVSRHI // QUOT * DVSRHI
1305 mul esi // QUOT * DVSRLO
1306 add edx,ecx // EDX:EAX = QUOT * DVSR
1307 jc short .....L4 // carry means Quotient is off by 1
1310 // do long compare here between original dividend and the result of the
1311 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
1312 // subtract one (1) from the quotient.
1315 cmp edx,DVNDHI // compare hi words of result and original
1316 ja short .....L4 // if result > original, do subtract
1317 jb short .....L5 // if result < original, we are ok
1318 cmp eax,DVNDLO // hi words are equal, compare lo words
1319 jbe short .....L5 // if less or equal we are ok, else subtract
1321 dec esi // subtract 1 from quotient
1322 sub eax,DVSRLO // subtract divisor from result
1325 xor ebx,ebx // ebx:esi <- quotient
1329 // Calculate remainder by subtracting the result from the original dividend.
1330 // Since the result is already in a register, we will do the subtract in the
1331 // opposite direction and negate the result.
1334 sub eax,DVNDLO // subtract dividend from result
1336 neg edx // otherwise, negate the result
1341 // Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
1349 // Just the cleanup left to do. edx:eax contains the quotient.
1350 // Restore the saved registers and return.
1360 fld qword ptr [ebp+8] // Load real from stack
1361 fld1 // Load constant 1
1362 fpatan // Take the arctangent
1369 sub esp,4 // Allocate temporary space
1370 fld qword ptr [ebp+8] // Load real from stack
1371 fstcw [ebp-2] // Save control word
1372 fclex // Clear exceptions
1373 mov word ptr [ebp-4],0xb63 // Rounding control word
1374 fldcw [ebp-4] // Set new rounding control
1375 frndint // Round to integer
1376 fclex // Clear exceptions
1377 fldcw [ebp-2] // Restore control word
1378 mov esp,ebp // Deallocate temporary space
1384 mov ebp,esp // Point to the stack frame
1385 fld qword ptr [ebp+8] // Load real from stack
1386 fcos // Take the cosine
1393 fld qword ptr [ebp+8] // Load real from stack
1394 fabs // Take the absolute value
1401 sub esp,4 // Allocate temporary space
1402 fld qword ptr [ebp+8] // Load real from stack
1403 fstcw [ebp-2] // Save control word
1404 fclex // Clear exceptions
1405 mov word ptr [ebp-4],0x763 // Rounding control word
1406 fldcw [ebp-4] // Set new rounding control
1407 frndint // Round to integer
1408 fclex // Clear exceptions
1409 fldcw [ebp-2] // Restore control word
1417 fld qword ptr [ebp+8] // Load real from stack
1418 fldln2 // Load log base e of 2
1419 fxch st(1) // Exchange st, st(1)
1420 fyl2x // Compute the natural log(x)
1427 sub esp,12 // Allocate temporary space
1428 push edi // Save register edi
1429 push eax // Save register eax
1430 mov dword ptr [ebp-12],0 // Set negation flag to zero
1431 fld qword ptr [ebp+16] // Load real from stack
1432 fld qword ptr [ebp+8] // Load real from stack
1433 mov edi,offset flat:fzero // Point to real zero
1434 fcom qword ptr [edi] // Compare x with zero
1435 fstsw ax // Get the FPU status word
1436 mov al,ah // Move condition flags to AL
1437 lahf // Load Flags into AH
1438 and al, 0b01000101 // Isolate C0, C2 and C3
1439 and ah,not 0b01000101 // Turn off CF, PF and ZF
1440 or ah,al // Set new CF, PF and ZF
1441 sahf // Store AH into Flags
1442 jb __fpow1 // Re-direct if x < 0
1443 ja __fpow3 // Re-direct if x > 0
1444 fxch // Swap st, st(1)
1445 fcom qword ptr [edi] // Compare y with zero
1446 fxch // Restore x as top of stack
1447 fstsw ax // Get the FPU status word
1448 mov al,ah // Move condition flags to AL
1449 lahf // Load Flags into AH
1450 and al, 0b01000101 // Isolate C0, C2 and C3
1451 and ah,not 0b01000101 // Turn off CF, PF and ZF
1452 or ah,al // Set new CF, PF and ZF
1453 sahf // Store AH into Flags
1454 ja __fpow3 // Re-direct if y > 0
1455 fstp st(1) // Set new stack top and pop
1456 mov eax,1 // Set domain error (EDOM)
1457 jmp __fpow5 // End of case
1458 __fpow1: fxch // Put y on top of stack
1459 fld st // Duplicate y as st(1)
1460 frndint // Round to integer
1461 fxch // Put y on top of stack
1462 fcomp // y = int(y) ?
1463 fstsw ax // Get the FPU status word
1464 mov al,ah // Move condition flags to AL
1465 lahf // Load Flags into AH
1466 and al, 0b01000101 // Isolate C0, C2 and C3
1467 and ah,not 0b01000101 // Turn off CF, PF and ZF
1468 or ah,al // Set new CF, PF and ZF
1469 sahf // Store AH into Flags
1470 je __fpow2 // Proceed if y = int(y)
1471 fstp st(1) // Set new stack top and pop
1472 fldz // Set result to zero
1473 fstp st(1) // Set new stack top and pop
1474 mov eax,1 // Set domain error (EDOM)
1475 jmp __fpow5 // End of case
1476 __fpow2: fist dword ptr [ebp-12] // Store y as integer
1477 and dword ptr [ebp-12],1 // Set bit if y is odd
1478 fxch // Put x on top of stack
1480 __fpow3: fldln2 // Load log base e of 2
1481 fxch st(1) // Exchange st, st(1)
1482 fyl2x // Compute the natural log(x)
1483 fmulp // Compute y * ln(x)
1484 fldl2e // Load log base 2(e)
1485 fmulp st(1),st // Multiply x * log base 2(e)
1486 fst st(1) // Push result
1487 frndint // Round to integer
1488 fsub st(1),st // Subtract
1489 fxch // Exchange st, st(1)
1490 f2xm1 // Compute 2 to the (x - 1)
1491 fld1 // Load real number 1
1493 fscale // Scale by power of 2
1494 fstp st(1) // Set new stack top and pop
1495 test dword ptr [ebp-12],1 // Negation required ?
1496 jz __fpow4 // No, re-direct
1497 fchs // Negate the result
1498 __fpow4: fstp qword ptr [ebp-8] // Save (double)pow(x, y)
1499 fld qword ptr [ebp-8] // Load (double)pow(x, y)
1501 fstsw ax // Get the FPU status word
1502 cmp ah,5 // Infinity ?
1503 jne __fpow6 // No, end of case
1504 mov eax,2 // Set range error (ERANGE)
1505 // Get errno pointer offset
1507 mov edi,0 // TODO: offset flat:__crt_errno
1508 mov edi,[edi] // Get C errno variable pointer
1509 mov dword ptr [edi],eax // Set errno
1510 __fpow6: pop eax // Restore register eax
1511 pop edi // Restore register edi
1512 mov esp,ebp // Deallocate temporary space
1517 push ebp // Save register bp
1518 mov ebp,esp // Point to the stack frame
1519 fld qword ptr [ebp+8] // Load real from stack
1520 fsin // Take the sine
1521 pop ebp // Restore register bp
1527 fld qword ptr [ebp+8] // Load real from stack
1528 fsqrt // Take the square root
1535 sub esp,4 // Allocate temporary space
1536 fld qword ptr [ebp+8] // Load real from stack
1537 fptan // Take the tangent
1538 fstp dword ptr [ebp-4] // Throw away the constant 1
1539 mov esp,ebp // Deallocate temporary space