ca1d6caf6eb1986d2f9c83bc1f8c4412f330ab14
[reactos.git] / reactos / lib / rtl / i386 / math.S
1 /*
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)
8 *
9 * Copyright (C) 2002 Michael Ringgaard.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
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.
24
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
35 * SUCH DAMAGE.
36 */
37
38 /* GLOBALS ****************************************************************/
39
40 .globl __ftol
41 .globl __aullshr
42 .globl __allrem
43 .globl __aulldiv
44 .globl __allshr
45 .globl __allshl
46 .globl __aullrem
47 .globl __allmul
48 .globl __alldiv
49 .globl __aulldvrm
50 .globl __alldvrm
51
52 /* FUNCTIONS ***************************************************************/
53
54 /*
55 * long long
56 * __alldiv(long long Dividend, long long Divisor);
57 *
58 * Parameters:
59 * [ESP+04h] - long long Dividend
60 * [ESP+0Ch] - long long Divisor
61 * Registers:
62 * Unknown
63 * Returns:
64 * EDX:EAX - long long quotient (Dividend/Divisor)
65 * Notes:
66 * Routine removes the arguments from the stack.
67 */
68 __alldiv:
69 call ___divdi3
70 ret $0x10
71
72 /*
73 * long long
74 * __allmul(long long Multiplier, long long Multiplicand);
75 *
76 * Parameters:
77 * [ESP+04h] - long long Multiplier
78 * [ESP+0Ch] - long long Multiplicand
79 * Registers:
80 * Unknown
81 * Returns:
82 * EDX:EAX - long long product (Multiplier*Multiplicand)
83 * Notes:
84 * Routine removes the arguments from the stack.
85 */
86 __allmul:
87 pushl %ebp
88 movl %esp, %ebp
89 pushl %edi
90 pushl %esi
91 pushl %ebx
92 subl $12, %esp
93 movl 16(%ebp), %ebx
94 movl 8(%ebp), %eax
95 mull %ebx
96 movl 20(%ebp), %ecx
97 movl %eax, -24(%ebp)
98 movl 8(%ebp), %eax
99 movl %edx, %esi
100 imull %ecx, %eax
101 addl %eax, %esi
102 movl 12(%ebp), %eax
103 imull %eax, %ebx
104 leal (%ebx,%esi), %eax
105 movl %eax, -20(%ebp)
106 movl -24(%ebp), %eax
107 movl -20(%ebp), %edx
108 addl $12, %esp
109 popl %ebx
110 popl %esi
111 popl %edi
112 popl %ebp
113 ret $0x10
114
115 /*
116 * unsigned long long
117 * __aullrem(unsigned long long Dividend, unsigned long long Divisor);
118 *
119 * Parameters:
120 * [ESP+04h] - unsigned long long Dividend
121 * [ESP+0Ch] - unsigned long long Divisor
122 * Registers:
123 * Unknown
124 * Returns:
125 * EDX:EAX - unsigned long long remainder (Dividend%Divisor)
126 * Notes:
127 * Routine removes the arguments from the stack.
128 */
129 __aullrem:
130 call ___umoddi3
131 ret $16
132
133 /*
134 * long long
135 * __allshl(long long Value, unsigned char Shift);
136 *
137 * Parameters:
138 * EDX:EAX - signed long long value to be shifted left
139 * CL - number of bits to shift by
140 * Registers:
141 * Destroys CL
142 * Returns:
143 * EDX:EAX - shifted value
144 */
145 __allshl:
146 shldl %cl, %eax, %edx
147 sall %cl, %eax
148 andl $32, %ecx
149 je 1f
150 movl %eax, %edx
151 xorl %eax, %eax
152 1:
153 ret
154
155 /*
156 * long long
157 * __allshr(long long Value, unsigned char Shift);
158 *
159 * Parameters:
160 * EDX:EAX - signed long long value to be shifted right
161 * CL - number of bits to shift by
162 * Registers:
163 * Destroys CL
164 * Returns:
165 * EDX:EAX - shifted value
166 */
167 __allshr:
168 shrdl %cl, %edx, %eax
169 sarl %cl, %edx
170 andl $32, %ecx
171 je 1f
172 movl %edx, %eax
173 sarl $31, %edx
174 1:
175 ret
176
177 /*
178 * unsigned long long
179 * __aulldiv(unsigned long long Dividend, unsigned long long Divisor);
180 *
181 * Parameters:
182 * [ESP+04h] - unsigned long long Dividend
183 * [ESP+0Ch] - unsigned long long Divisor
184 * Registers:
185 * Unknown
186 * Returns:
187 * EDX:EAX - unsigned long long quotient (Dividend/Divisor)
188 * Notes:
189 * Routine removes the arguments from the stack.
190 */
191 __aulldiv:
192 call ___udivdi3
193 ret $16
194
195 /*
196 * unsigned long long
197 * __aullshr(unsigned long long Value, unsigned char Shift);
198 *
199 * Parameters:
200 * EDX:EAX - unsigned long long value to be shifted right
201 * CL - number of bits to shift by
202 * Registers:
203 * Destroys CL
204 * Returns:
205 * EDX:EAX - shifted value
206 */
207 __aullshr:
208 shrdl %cl, %edx, %eax
209 shrl %cl, %edx
210 andl $32, %ecx
211 je 1f
212 movl %edx, %eax
213 1:
214 ret
215
216 /*
217 * long long
218 * __allrem(long long Dividend, long long Divisor);
219 *
220 * Parameters:
221 * [ESP+04h] - long long Dividend
222 * [ESP+0Ch] - long long Divisor
223 * Registers:
224 * Unknown
225 * Returns:
226 * EDX:EAX - long long remainder (Dividend/Divisor)
227 * Notes:
228 * Routine removes the arguments from the stack.
229 */
230 __allrem:
231 call ___moddi3
232 ret $16
233
234 .intel_syntax noprefix
235
236 /*
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.
240 */
241 __ftol:
242 /* Set up stack frame */
243 push ebp
244 mov ebp, esp
245
246 /* Set "round towards zero" mode */
247 fstcw [ebp-2]
248 wait
249 mov ax, [ebp-2]
250 or ah, 0xC
251 mov [ebp-4], ax
252 fldcw [ebp-4]
253
254 /* Do the conversion */
255 fistp qword ptr [ebp-12]
256
257 /* Restore rounding mode */
258 fldcw [ebp-2]
259
260 /* Return value */
261 mov eax, [ebp-12]
262 mov edx, [ebp-8]
263
264 /* Remove stack frame and return*/
265 leave
266 ret
267
268 __alldvrm:
269 push edi
270 push esi
271 push ebp
272
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)):
276 //
277 // -----------------
278 // | |
279 // |---------------|
280 // | |
281 // |--divisor (b)--|
282 // | |
283 // |---------------|
284 // | |
285 // |--dividend (a)-|
286 // | |
287 // |---------------|
288 // | return addr** |
289 // |---------------|
290 // | EDI |
291 // |---------------|
292 // | ESI |
293 // |---------------|
294 // ESP---->| EBP |
295 // -----------------
296 //
297
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)
302
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.
306
307 xor edi,edi // result sign assumed positive
308 xor ebp,ebp // result sign assumed positive
309
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
317 neg edx
318 sbb eax,0
319 mov DVNDHI,eax // save positive value
320 mov DVNDLO,edx
321 L1:
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
328 neg edx
329 sbb eax,0
330 mov DVSRHI,eax // save positive value
331 mov DVSRLO,edx
332 L2:
333
334 //
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.
338 //
339 // NOTE - eax currently contains the high order word of DVSR
340 //
341
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
346 xor edx,edx
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
352 //
353 // Now we need to do a multiply so that we can compute the remainder.
354 //
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
362
363 //
364 // Here we do it the hard way. Remember, eax contains the high word of DVSR
365 //
366
367 L3:
368 mov ebx,eax // ebx:ecx <- divisor
369 mov ecx,DVSRLO
370 mov edx,DVNDHI // edx:eax <- dividend
371 mov eax,DVNDLO
372 L5:
373 shr ebx,1 // shift divisor right one bit
374 rcr ecx,1
375 shr edx,1 // shift dividend right one bit
376 rcr eax,1
377 or ebx,ebx
378 jnz short L5 // loop until divisor < 4194304K
379 div ecx // now divide, ignore remainder
380 mov esi,eax // save quotient
381
382 //
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.
387 //
388
389 mul dword ptr DVSRHI // QUOT * DVSRHI
390 mov ecx,eax
391 mov eax,DVSRLO
392 mul esi // QUOT * DVSRLO
393 add edx,ecx // EDX:EAX = QUOT * DVSR
394 jc short L6 // carry means Quotient is off by 1
395
396 //
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.
400 //
401
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
407 L6:
408 dec esi // subtract 1 from quotient
409 sub eax,DVSRLO // subtract divisor from result
410 sbb edx,DVSRHI
411 L7:
412 xor ebx,ebx // ebx:esi <- quotient
413
414 L4:
415 //
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.
419 //
420
421 sub eax,DVNDLO // subtract dividend from result
422 sbb edx,DVNDHI
423
424 //
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.
429 //
430
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
434 neg eax
435 sbb edx,0
436
437 //
438 // Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
439 //
440 L9:
441 mov ecx,edx
442 mov edx,ebx
443 mov ebx,ecx
444 mov ecx,eax
445 mov eax,esi
446
447 //
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.
450 //
451
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
455 neg eax
456 sbb edx,0
457
458 //
459 // Restore the saved registers and return.
460 //
461
462 L8:
463 pop ebp
464 pop esi
465 pop edi
466
467 ret 16
468
469 __aulldvrm:
470
471 // ulldvrm - unsigned long divide and remainder
472 //
473 // Purpose:
474 // Does a unsigned long divide and remainder of the arguments. Arguments
475 // are not changed.
476 //
477 // Entry:
478 // Arguments are passed on the stack:
479 // 1st pushed: divisor (QWORD)
480 // 2nd pushed: dividend (QWORD)
481 //
482 // Exit:
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.
486 //
487 // Uses:
488 // ECX
489 //
490 push esi
491
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)):
495 //
496 // -----------------
497 // | |
498 // |---------------|
499 // | |
500 // |--divisor (b)--|
501 // | |
502 // |---------------|
503 // | |
504 // |--dividend (a)-|
505 // | |
506 // |---------------|
507 // | return addr** |
508 // |---------------|
509 // ESP---->| ESI |
510 // -----------------
511 //
512
513 #undef DVNDLO
514 #undef DVNDHI
515 #undef DVSRLO
516 #undef DVSRHI
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)
521
522 //
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.
526 //
527
528 mov eax,DVSRHI // check to see if divisor < 4194304K
529 or eax,eax
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
533 xor edx,edx
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
539
540 //
541 // Now we need to do a multiply so that we can compute the remainder.
542 //
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
550
551 //
552 // Here we do it the hard way. Remember, eax contains DVSRHI
553 //
554
555 .L1:
556 mov ecx,eax // ecx:ebx <- divisor
557 mov ebx,DVSRLO
558 mov edx,DVNDHI // edx:eax <- dividend
559 mov eax,DVNDLO
560 .L3:
561 shr ecx,1 // shift divisor right one bit// hi bit <- 0
562 rcr ebx,1
563 shr edx,1 // shift dividend right one bit// hi bit <- 0
564 rcr eax,1
565 or ecx,ecx
566 jnz short .L3 // loop until divisor < 4194304K
567 div ebx // now divide, ignore remainder
568 mov esi,eax // save quotient
569
570 //
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.
575 //
576
577 mul dword ptr DVSRHI // QUOT * DVSRHI
578 mov ecx,eax
579 mov eax,DVSRLO
580 mul esi // QUOT * DVSRLO
581 add edx,ecx // EDX:EAX = QUOT * DVSR
582 jc short .L4 // carry means Quotient is off by 1
583
584 //
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.
588 //
589
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
595 .L4:
596 dec esi // subtract 1 from quotient
597 sub eax,DVSRLO // subtract divisor from result
598 sbb edx,DVSRHI
599 .L5:
600 xor ebx,ebx // ebx:esi <- quotient
601
602 .L2:
603 //
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.
607 //
608
609 sub eax,DVNDLO // subtract dividend from result
610 sbb edx,DVNDHI
611 neg edx // otherwise, negate the result
612 neg eax
613 sbb edx,0
614
615 //
616 // Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
617 //
618 mov ecx,edx
619 mov edx,ebx
620 mov ebx,ecx
621 mov ecx,eax
622 mov eax,esi
623 //
624 // Just the cleanup left to do. edx:eax contains the quotient.
625 // Restore the saved registers and return.
626 //
627
628 pop esi
629
630 ret 16
631