import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / i386 / gen / _div64.s
blob37e341149e14d165a3e8d62f40d7bd5da20b6f37
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 .file "_div64.s"
28 #include "SYS.h"
31 * C support for 64-bit modulo and division.
32 * Hand-customized compiler output - see comments for details.
36 * int32_t/int64_t division/manipulation
38 * Hand-customized compiler output: the non-GCC entry points depart from
39 * the SYS V ABI by requiring their arguments to be popped, and in the
40 * [u]divrem64 cases returning the remainder in %ecx:%esi. Note the
41 * compiler-generated use of %edx:%eax for the first argument of
42 * internal entry points.
44 * Inlines for speed:
45 * - counting the number of leading zeros in a word
46 * - multiplying two 32-bit numbers giving a 64-bit result
47 * - dividing a 64-bit number by a 32-bit number, giving both quotient
48 * and remainder
49 * - subtracting two 64-bit results
51 / #define LO(X) ((uint32_t)(X) & 0xffffffff)
52 / #define HI(X) ((uint32_t)((X) >> 32) & 0xffffffff)
53 / #define HILO(H, L) (((uint64_t)(H) << 32) + (L))
55 / /* give index of highest bit */
56 / #define HIBIT(a, r) \
57 / asm("bsrl %1,%0": "=r"((uint32_t)(r)) : "g" (a))
59 / /* multiply two uint32_ts resulting in a uint64_t */
60 / #define A_MUL32(a, b, lo, hi) \
61 / asm("mull %2" \
62 / : "=a"((uint32_t)(lo)), "=d"((uint32_t)(hi)) : "g" (b), "0"(a))
64 / /* divide a uint64_t by a uint32_t */
65 / #define A_DIV32(lo, hi, b, q, r) \
66 / asm("divl %2" \
67 / : "=a"((uint32_t)(q)), "=d"((uint32_t)(r)) \
68 / : "g" (b), "0"((uint32_t)(lo)), "1"((uint32_t)hi))
70 / /* subtract two uint64_ts (with borrow) */
71 / #define A_SUB2(bl, bh, al, ah) \
72 / asm("subl %4,%0\n\tsbbl %5,%1" \
73 / : "=&r"((uint32_t)(al)), "=r"((uint32_t)(ah)) \
74 / : "0"((uint32_t)(al)), "1"((uint32_t)(ah)), "g"((uint32_t)(bl)), \
75 / "g"((uint32_t)(bh)))
77 / /*
78 / * Unsigned division with remainder.
79 / * Divide two uint64_ts, and calculate remainder.
80 / */
81 / uint64_t
82 / UDivRem(uint64_t x, uint64_t y, uint64_t * pmod)
83 / {
84 / /* simple cases: y is a single uint32_t */
85 / if (HI(y) == 0) {
86 / uint32_t div_hi, div_rem;
87 / uint32_t q0, q1;
89 / /* calculate q1 */
90 / if (HI(x) < LO(y)) {
91 / /* result is a single uint32_t, use one division */
92 / q1 = 0;
93 / div_hi = HI(x);
94 / } else {
95 / /* result is a double uint32_t, use two divisions */
96 / A_DIV32(HI(x), 0, LO(y), q1, div_hi);
97 / }
99 / /* calculate q0 and remainder */
100 / A_DIV32(LO(x), div_hi, LO(y), q0, div_rem);
102 / /* return remainder */
103 / *pmod = div_rem;
105 / /* return result */
106 / return (HILO(q1, q0));
108 / } else if (HI(x) < HI(y)) {
109 / /* HI(x) < HI(y) => x < y => result is 0 */
111 / /* return remainder */
112 / *pmod = x;
114 / /* return result */
115 / return (0);
117 / } else {
118 / /*
119 / * uint64_t by uint64_t division, resulting in a one-uint32_t
120 / * result
121 / */
122 / uint32_t y0, y1;
123 / uint32_t x1, x0;
124 / uint32_t q0;
125 / uint32_t normshift;
127 / /* normalize by shifting x and y so MSB(y) == 1 */
128 / HIBIT(HI(y), normshift); /* index of highest 1 bit */
129 / normshift = 31 - normshift;
131 / if (normshift == 0) {
132 / /* no shifting needed, and x < 2*y so q <= 1 */
133 / y1 = HI(y);
134 / y0 = LO(y);
135 / x1 = HI(x);
136 / x0 = LO(x);
138 / /* if x >= y then q = 1 (note x1 >= y1) */
139 / if (x1 > y1 || x0 >= y0) {
140 / q0 = 1;
141 / /* subtract y from x to get remainder */
142 / A_SUB2(y0, y1, x0, x1);
143 / } else {
144 / q0 = 0;
147 / /* return remainder */
148 / *pmod = HILO(x1, x0);
150 / /* return result */
151 / return (q0);
153 / } else {
154 / /*
155 / * the last case: result is one uint32_t, but we need to
156 / * normalize
157 / */
158 / uint64_t dt;
159 / uint32_t t0, t1, x2;
161 / /* normalize y */
162 / dt = (y << normshift);
163 / y1 = HI(dt);
164 / y0 = LO(dt);
166 / /* normalize x (we need 3 uint32_ts!!!) */
167 / x2 = (HI(x) >> (32 - normshift));
168 / dt = (x << normshift);
169 / x1 = HI(dt);
170 / x0 = LO(dt);
172 / /* estimate q0, and reduce x to a two uint32_t value */
173 / A_DIV32(x1, x2, y1, q0, x1);
175 / /* adjust q0 down if too high */
176 / /*
177 / * because of the limited range of x2 we can only be
178 / * one off
179 / */
180 / A_MUL32(y0, q0, t0, t1);
181 / if (t1 > x1 || (t1 == x1 && t0 > x0)) {
182 / q0--;
183 / A_SUB2(y0, y1, t0, t1);
185 / /* return remainder */
186 / /* subtract product from x to get remainder */
187 / A_SUB2(t0, t1, x0, x1);
188 / *pmod = (HILO(x1, x0) >> normshift);
190 / /* return result */
191 / return (q0);
195 ENTRY(UDivRem)
196 pushl %ebp
197 pushl %edi
198 pushl %esi
199 subl $48, %esp
200 movl 68(%esp), %edi / y,
201 testl %edi, %edi / tmp63
202 movl %eax, 40(%esp) / x, x
203 movl %edx, 44(%esp) / x, x
204 movl %edi, %esi /, tmp62
205 movl %edi, %ecx / tmp62, tmp63
206 jne .LL2
207 movl %edx, %eax /, tmp68
208 cmpl 64(%esp), %eax / y, tmp68
209 jae .LL21
210 .LL4:
211 movl 72(%esp), %ebp / pmod,
212 xorl %esi, %esi / <result>
213 movl 40(%esp), %eax / x, q0
214 movl %ecx, %edi / <result>, <result>
215 divl 64(%esp) / y
216 movl %edx, (%ebp) / div_rem,
217 xorl %edx, %edx / q0
218 addl %eax, %esi / q0, <result>
219 movl $0, 4(%ebp)
220 adcl %edx, %edi / q0, <result>
221 addl $48, %esp
222 movl %esi, %eax / <result>, <result>
223 popl %esi
224 movl %edi, %edx / <result>, <result>
225 popl %edi
226 popl %ebp
228 .align 16
229 .LL2:
230 movl 44(%esp), %eax / x,
231 xorl %edx, %edx
232 cmpl %esi, %eax / tmp62, tmp5
233 movl %eax, 32(%esp) / tmp5,
234 movl %edx, 36(%esp)
235 jae .LL6
236 movl 72(%esp), %esi / pmod,
237 movl 40(%esp), %ebp / x,
238 movl 44(%esp), %ecx / x,
239 movl %ebp, (%esi)
240 movl %ecx, 4(%esi)
241 xorl %edi, %edi / <result>
242 xorl %esi, %esi / <result>
243 .LL22:
244 addl $48, %esp
245 movl %esi, %eax / <result>, <result>
246 popl %esi
247 movl %edi, %edx / <result>, <result>
248 popl %edi
249 popl %ebp
251 .align 16
252 .LL21:
253 movl %edi, %edx / tmp63, div_hi
254 divl 64(%esp) / y
255 movl %eax, %ecx /, q1
256 jmp .LL4
257 .align 16
258 .LL6:
259 movl $31, %edi /, tmp87
260 bsrl %esi,%edx / tmp62, normshift
261 subl %edx, %edi / normshift, tmp87
262 movl %edi, 28(%esp) / tmp87,
263 jne .LL8
264 movl 32(%esp), %edx /, x1
265 cmpl %ecx, %edx / y1, x1
266 movl 64(%esp), %edi / y, y0
267 movl 40(%esp), %esi / x, x0
268 ja .LL10
269 xorl %ebp, %ebp / q0
270 cmpl %edi, %esi / y0, x0
271 jb .LL11
272 .LL10:
273 movl $1, %ebp /, q0
274 subl %edi,%esi / y0, x0
275 sbbl %ecx,%edx / tmp63, x1
276 .LL11:
277 movl %edx, %ecx / x1, x1
278 xorl %edx, %edx / x1
279 xorl %edi, %edi / x0
280 addl %esi, %edx / x0, x1
281 adcl %edi, %ecx / x0, x1
282 movl 72(%esp), %esi / pmod,
283 movl %edx, (%esi) / x1,
284 movl %ecx, 4(%esi) / x1,
285 xorl %edi, %edi / <result>
286 movl %ebp, %esi / q0, <result>
287 jmp .LL22
288 .align 16
289 .LL8:
290 movb 28(%esp), %cl
291 movl 64(%esp), %esi / y, dt
292 movl 68(%esp), %edi / y, dt
293 shldl %esi, %edi /, dt, dt
294 sall %cl, %esi /, dt
295 andl $32, %ecx
296 jne .LL23
297 .LL17:
298 movl $32, %ecx /, tmp102
299 subl 28(%esp), %ecx /, tmp102
300 movl %esi, %ebp / dt, y0
301 movl 32(%esp), %esi
302 shrl %cl, %esi / tmp102,
303 movl %edi, 24(%esp) / tmp99,
304 movb 28(%esp), %cl
305 movl %esi, 12(%esp) /, x2
306 movl 44(%esp), %edi / x, dt
307 movl 40(%esp), %esi / x, dt
308 shldl %esi, %edi /, dt, dt
309 sall %cl, %esi /, dt
310 andl $32, %ecx
311 je .LL18
312 movl %esi, %edi / dt, dt
313 xorl %esi, %esi / dt
314 .LL18:
315 movl %edi, %ecx / dt,
316 movl %edi, %eax / tmp2,
317 movl %ecx, (%esp)
318 movl 12(%esp), %edx / x2,
319 divl 24(%esp)
320 movl %edx, %ecx /, x1
321 xorl %edi, %edi
322 movl %eax, 20(%esp)
323 movl %ebp, %eax / y0, t0
324 mull 20(%esp)
325 cmpl %ecx, %edx / x1, t1
326 movl %edi, 4(%esp)
327 ja .LL14
328 je .LL24
329 .LL15:
330 movl %ecx, %edi / x1,
331 subl %eax,%esi / t0, x0
332 sbbl %edx,%edi / t1,
333 movl %edi, %eax /, x1
334 movl %eax, %edx / x1, x1
335 xorl %eax, %eax / x1
336 xorl %ebp, %ebp / x0
337 addl %esi, %eax / x0, x1
338 adcl %ebp, %edx / x0, x1
339 movb 28(%esp), %cl
340 shrdl %edx, %eax /, x1, x1
341 shrl %cl, %edx /, x1
342 andl $32, %ecx
343 je .LL16
344 movl %edx, %eax / x1, x1
345 xorl %edx, %edx / x1
346 .LL16:
347 movl 72(%esp), %ecx / pmod,
348 movl 20(%esp), %esi /, <result>
349 xorl %edi, %edi / <result>
350 movl %eax, (%ecx) / x1,
351 movl %edx, 4(%ecx) / x1,
352 jmp .LL22
353 .align 16
354 .LL24:
355 cmpl %esi, %eax / x0, t0
356 jbe .LL15
357 .LL14:
358 decl 20(%esp)
359 subl %ebp,%eax / y0, t0
360 sbbl 24(%esp),%edx /, t1
361 jmp .LL15
362 .LL23:
363 movl %esi, %edi / dt, dt
364 xorl %esi, %esi / dt
365 jmp .LL17
366 SET_SIZE(UDivRem)
369 * Unsigned division without remainder.
371 / uint64_t
372 / UDiv(uint64_t x, uint64_t y)
374 / if (HI(y) == 0) {
375 / /* simple cases: y is a single uint32_t */
376 / uint32_t div_hi, div_rem;
377 / uint32_t q0, q1;
379 / /* calculate q1 */
380 / if (HI(x) < LO(y)) {
381 / /* result is a single uint32_t, use one division */
382 / q1 = 0;
383 / div_hi = HI(x);
384 / } else {
385 / /* result is a double uint32_t, use two divisions */
386 / A_DIV32(HI(x), 0, LO(y), q1, div_hi);
389 / /* calculate q0 and remainder */
390 / A_DIV32(LO(x), div_hi, LO(y), q0, div_rem);
392 / /* return result */
393 / return (HILO(q1, q0));
395 / } else if (HI(x) < HI(y)) {
396 / /* HI(x) < HI(y) => x < y => result is 0 */
398 / /* return result */
399 / return (0);
401 / } else {
402 / /*
403 / * uint64_t by uint64_t division, resulting in a one-uint32_t
404 / * result
405 / */
406 / uint32_t y0, y1;
407 / uint32_t x1, x0;
408 / uint32_t q0;
409 / unsigned normshift;
411 / /* normalize by shifting x and y so MSB(y) == 1 */
412 / HIBIT(HI(y), normshift); /* index of highest 1 bit */
413 / normshift = 31 - normshift;
415 / if (normshift == 0) {
416 / /* no shifting needed, and x < 2*y so q <= 1 */
417 / y1 = HI(y);
418 / y0 = LO(y);
419 / x1 = HI(x);
420 / x0 = LO(x);
422 / /* if x >= y then q = 1 (note x1 >= y1) */
423 / if (x1 > y1 || x0 >= y0) {
424 / q0 = 1;
425 / /* subtract y from x to get remainder */
426 / /* A_SUB2(y0, y1, x0, x1); */
427 / } else {
428 / q0 = 0;
431 / /* return result */
432 / return (q0);
434 / } else {
435 / /*
436 / * the last case: result is one uint32_t, but we need to
437 / * normalize
438 / */
439 / uint64_t dt;
440 / uint32_t t0, t1, x2;
442 / /* normalize y */
443 / dt = (y << normshift);
444 / y1 = HI(dt);
445 / y0 = LO(dt);
447 / /* normalize x (we need 3 uint32_ts!!!) */
448 / x2 = (HI(x) >> (32 - normshift));
449 / dt = (x << normshift);
450 / x1 = HI(dt);
451 / x0 = LO(dt);
453 / /* estimate q0, and reduce x to a two uint32_t value */
454 / A_DIV32(x1, x2, y1, q0, x1);
456 / /* adjust q0 down if too high */
457 / /*
458 / * because of the limited range of x2 we can only be
459 / * one off
460 / */
461 / A_MUL32(y0, q0, t0, t1);
462 / if (t1 > x1 || (t1 == x1 && t0 > x0)) {
463 / q0--;
465 / /* return result */
466 / return (q0);
470 ENTRY(UDiv)
471 pushl %ebp
472 pushl %edi
473 pushl %esi
474 subl $40, %esp
475 movl %edx, 36(%esp) / x, x
476 movl 60(%esp), %edx / y,
477 testl %edx, %edx / tmp62
478 movl %eax, 32(%esp) / x, x
479 movl %edx, %ecx / tmp61, tmp62
480 movl %edx, %eax /, tmp61
481 jne .LL26
482 movl 36(%esp), %esi / x,
483 cmpl 56(%esp), %esi / y, tmp67
484 movl %esi, %eax /, tmp67
485 movl %esi, %edx / tmp67, div_hi
486 jb .LL28
487 movl %ecx, %edx / tmp62, div_hi
488 divl 56(%esp) / y
489 movl %eax, %ecx /, q1
490 .LL28:
491 xorl %esi, %esi / <result>
492 movl %ecx, %edi / <result>, <result>
493 movl 32(%esp), %eax / x, q0
494 xorl %ecx, %ecx / q0
495 divl 56(%esp) / y
496 addl %eax, %esi / q0, <result>
497 adcl %ecx, %edi / q0, <result>
498 .LL25:
499 addl $40, %esp
500 movl %esi, %eax / <result>, <result>
501 popl %esi
502 movl %edi, %edx / <result>, <result>
503 popl %edi
504 popl %ebp
506 .align 16
507 .LL26:
508 movl 36(%esp), %esi / x,
509 xorl %edi, %edi
510 movl %esi, 24(%esp) / tmp1,
511 movl %edi, 28(%esp)
512 xorl %esi, %esi / <result>
513 xorl %edi, %edi / <result>
514 cmpl %eax, 24(%esp) / tmp61,
515 jb .LL25
516 bsrl %eax,%ebp / tmp61, normshift
517 movl $31, %eax /, tmp85
518 subl %ebp, %eax / normshift, normshift
519 jne .LL32
520 movl 24(%esp), %eax /, x1
521 cmpl %ecx, %eax / tmp62, x1
522 movl 56(%esp), %esi / y, y0
523 movl 32(%esp), %edx / x, x0
524 ja .LL34
525 xorl %eax, %eax / q0
526 cmpl %esi, %edx / y0, x0
527 jb .LL35
528 .LL34:
529 movl $1, %eax /, q0
530 .LL35:
531 movl %eax, %esi / q0, <result>
532 xorl %edi, %edi / <result>
533 .LL45:
534 addl $40, %esp
535 movl %esi, %eax / <result>, <result>
536 popl %esi
537 movl %edi, %edx / <result>, <result>
538 popl %edi
539 popl %ebp
541 .align 16
542 .LL32:
543 movb %al, %cl
544 movl 56(%esp), %esi / y,
545 movl 60(%esp), %edi / y,
546 shldl %esi, %edi
547 sall %cl, %esi
548 andl $32, %ecx
549 jne .LL43
550 .LL40:
551 movl $32, %ecx /, tmp96
552 subl %eax, %ecx / normshift, tmp96
553 movl %edi, %edx
554 movl %edi, 20(%esp) /, dt
555 movl 24(%esp), %ebp /, x2
556 xorl %edi, %edi
557 shrl %cl, %ebp / tmp96, x2
558 movl %esi, 16(%esp) /, dt
559 movb %al, %cl
560 movl 32(%esp), %esi / x, dt
561 movl %edi, 12(%esp)
562 movl 36(%esp), %edi / x, dt
563 shldl %esi, %edi /, dt, dt
564 sall %cl, %esi /, dt
565 andl $32, %ecx
566 movl %edx, 8(%esp)
567 je .LL41
568 movl %esi, %edi / dt, dt
569 xorl %esi, %esi / dt
570 .LL41:
571 xorl %ecx, %ecx
572 movl %edi, %eax / tmp1,
573 movl %ebp, %edx / x2,
574 divl 8(%esp)
575 movl %edx, %ebp /, x1
576 movl %ecx, 4(%esp)
577 movl %eax, %ecx /, q0
578 movl 16(%esp), %eax / dt,
579 mull %ecx / q0
580 cmpl %ebp, %edx / x1, t1
581 movl %edi, (%esp)
582 movl %esi, %edi / dt, x0
583 ja .LL38
584 je .LL44
585 .LL39:
586 movl %ecx, %esi / q0, <result>
587 .LL46:
588 xorl %edi, %edi / <result>
589 jmp .LL45
590 .LL44:
591 cmpl %edi, %eax / x0, t0
592 jbe .LL39
593 .LL38:
594 decl %ecx / q0
595 movl %ecx, %esi / q0, <result>
596 jmp .LL46
597 .LL43:
598 movl %esi, %edi
599 xorl %esi, %esi
600 jmp .LL40
601 SET_SIZE(UDiv)
604 * __udiv64
606 * Perform division of two unsigned 64-bit quantities, returning the
607 * quotient in %edx:%eax. __udiv64 pops the arguments on return,
609 ENTRY(__udiv64)
610 movl 4(%esp), %eax / x, x
611 movl 8(%esp), %edx / x, x
612 pushl 16(%esp) / y
613 pushl 16(%esp)
614 call UDiv
615 addl $8, %esp
616 ret $16
617 SET_SIZE(__udiv64)
620 * __urem64
622 * Perform division of two unsigned 64-bit quantities, returning the
623 * remainder in %edx:%eax. __urem64 pops the arguments on return
625 ENTRY(__urem64)
626 subl $12, %esp
627 movl %esp, %ecx /, tmp65
628 movl 16(%esp), %eax / x, x
629 movl 20(%esp), %edx / x, x
630 pushl %ecx / tmp65
631 pushl 32(%esp) / y
632 pushl 32(%esp)
633 call UDivRem
634 movl 12(%esp), %eax / rem, rem
635 movl 16(%esp), %edx / rem, rem
636 addl $24, %esp
637 ret $16
638 SET_SIZE(__urem64)
641 * __div64
643 * Perform division of two signed 64-bit quantities, returning the
644 * quotient in %edx:%eax. __div64 pops the arguments on return.
646 / int64_t
647 / __div64(int64_t x, int64_t y)
649 / int negative;
650 / uint64_t xt, yt, r;
652 / if (x < 0) {
653 / xt = -(uint64_t) x;
654 / negative = 1;
655 / } else {
656 / xt = x;
657 / negative = 0;
659 / if (y < 0) {
660 / yt = -(uint64_t) y;
661 / negative ^= 1;
662 / } else {
663 / yt = y;
665 / r = UDiv(xt, yt);
666 / return (negative ? (int64_t) - r : r);
668 ENTRY(__div64)
669 pushl %ebp
670 pushl %edi
671 pushl %esi
672 subl $8, %esp
673 movl 28(%esp), %edx / x, x
674 testl %edx, %edx / x
675 movl 24(%esp), %eax / x, x
676 movl 32(%esp), %esi / y, y
677 movl 36(%esp), %edi / y, y
678 js .LL84
679 xorl %ebp, %ebp / negative
680 testl %edi, %edi / y
681 movl %eax, (%esp) / x, xt
682 movl %edx, 4(%esp) / x, xt
683 movl %esi, %eax / y, yt
684 movl %edi, %edx / y, yt
685 js .LL85
686 .LL82:
687 pushl %edx / yt
688 pushl %eax / yt
689 movl 8(%esp), %eax / xt, xt
690 movl 12(%esp), %edx / xt, xt
691 call UDiv
692 popl %ecx
693 testl %ebp, %ebp / negative
694 popl %esi
695 je .LL83
696 negl %eax / r
697 adcl $0, %edx /, r
698 negl %edx / r
699 .LL83:
700 addl $8, %esp
701 popl %esi
702 popl %edi
703 popl %ebp
704 ret $16
705 .align 16
706 .LL84:
707 negl %eax / x
708 adcl $0, %edx /, x
709 negl %edx / x
710 testl %edi, %edi / y
711 movl %eax, (%esp) / x, xt
712 movl %edx, 4(%esp) / x, xt
713 movl $1, %ebp /, negative
714 movl %esi, %eax / y, yt
715 movl %edi, %edx / y, yt
716 jns .LL82
717 .align 16
718 .LL85:
719 negl %eax / yt
720 adcl $0, %edx /, yt
721 negl %edx / yt
722 xorl $1, %ebp /, negative
723 jmp .LL82
724 SET_SIZE(__div64)
727 * __rem64
729 * Perform division of two signed 64-bit quantities, returning the
730 * remainder in %edx:%eax. __rem64 pops the arguments on return.
732 / int64_t
733 / __rem64(int64_t x, int64_t y)
735 / uint64_t xt, yt, rem;
737 / if (x < 0) {
738 / xt = -(uint64_t) x;
739 / } else {
740 / xt = x;
742 / if (y < 0) {
743 / yt = -(uint64_t) y;
744 / } else {
745 / yt = y;
747 / (void) UDivRem(xt, yt, &rem);
748 / return (x < 0 ? (int64_t) - rem : rem);
750 ENTRY(__rem64)
751 pushl %edi
752 pushl %esi
753 subl $20, %esp
754 movl 36(%esp), %ecx / x,
755 movl 32(%esp), %esi / x,
756 movl 36(%esp), %edi / x,
757 testl %ecx, %ecx
758 movl 40(%esp), %eax / y, y
759 movl 44(%esp), %edx / y, y
760 movl %esi, (%esp) /, xt
761 movl %edi, 4(%esp) /, xt
762 js .LL92
763 testl %edx, %edx / y
764 movl %eax, %esi / y, yt
765 movl %edx, %edi / y, yt
766 js .LL93
767 .LL90:
768 leal 8(%esp), %eax /, tmp66
769 pushl %eax / tmp66
770 pushl %edi / yt
771 pushl %esi / yt
772 movl 12(%esp), %eax / xt, xt
773 movl 16(%esp), %edx / xt, xt
774 call UDivRem
775 addl $12, %esp
776 movl 36(%esp), %edi / x,
777 testl %edi, %edi
778 movl 8(%esp), %eax / rem, rem
779 movl 12(%esp), %edx / rem, rem
780 js .LL94
781 addl $20, %esp
782 popl %esi
783 popl %edi
784 ret $16
785 .align 16
786 .LL92:
787 negl %esi
788 adcl $0, %edi
789 negl %edi
790 testl %edx, %edx / y
791 movl %esi, (%esp) /, xt
792 movl %edi, 4(%esp) /, xt
793 movl %eax, %esi / y, yt
794 movl %edx, %edi / y, yt
795 jns .LL90
796 .align 16
797 .LL93:
798 negl %esi / yt
799 adcl $0, %edi /, yt
800 negl %edi / yt
801 jmp .LL90
802 .align 16
803 .LL94:
804 negl %eax / rem
805 adcl $0, %edx /, rem
806 addl $20, %esp
807 popl %esi
808 negl %edx / rem
809 popl %edi
810 ret $16
811 SET_SIZE(__rem64)
814 * __udivrem64
816 * Perform division of two unsigned 64-bit quantities, returning the
817 * quotient in %edx:%eax, and the remainder in %ecx:%esi. __udivrem64
818 * pops the arguments on return.
820 ENTRY(__udivrem64)
821 subl $12, %esp
822 movl %esp, %ecx /, tmp64
823 movl 16(%esp), %eax / x, x
824 movl 20(%esp), %edx / x, x
825 pushl %ecx / tmp64
826 pushl 32(%esp) / y
827 pushl 32(%esp)
828 call UDivRem
829 movl 16(%esp), %ecx / rem, tmp63
830 movl 12(%esp), %esi / rem
831 addl $24, %esp
832 ret $16
833 SET_SIZE(__udivrem64)
836 * Signed division with remainder.
838 / int64_t
839 / SDivRem(int64_t x, int64_t y, int64_t * pmod)
841 / int negative;
842 / uint64_t xt, yt, r, rem;
844 / if (x < 0) {
845 / xt = -(uint64_t) x;
846 / negative = 1;
847 / } else {
848 / xt = x;
849 / negative = 0;
851 / if (y < 0) {
852 / yt = -(uint64_t) y;
853 / negative ^= 1;
854 / } else {
855 / yt = y;
857 / r = UDivRem(xt, yt, &rem);
858 / *pmod = (x < 0 ? (int64_t) - rem : rem);
859 / return (negative ? (int64_t) - r : r);
861 ENTRY(SDivRem)
862 pushl %ebp
863 pushl %edi
864 pushl %esi
865 subl $24, %esp
866 testl %edx, %edx / x
867 movl %edx, %edi / x, x
868 js .LL73
869 movl 44(%esp), %esi / y,
870 xorl %ebp, %ebp / negative
871 testl %esi, %esi
872 movl %edx, 12(%esp) / x, xt
873 movl %eax, 8(%esp) / x, xt
874 movl 40(%esp), %edx / y, yt
875 movl 44(%esp), %ecx / y, yt
876 js .LL74
877 .LL70:
878 leal 16(%esp), %eax /, tmp70
879 pushl %eax / tmp70
880 pushl %ecx / yt
881 pushl %edx / yt
882 movl 20(%esp), %eax / xt, xt
883 movl 24(%esp), %edx / xt, xt
884 call UDivRem
885 movl %edx, 16(%esp) /, r
886 movl %eax, 12(%esp) /, r
887 addl $12, %esp
888 testl %edi, %edi / x
889 movl 16(%esp), %edx / rem, rem
890 movl 20(%esp), %ecx / rem, rem
891 js .LL75
892 .LL71:
893 movl 48(%esp), %edi / pmod, pmod
894 testl %ebp, %ebp / negative
895 movl %edx, (%edi) / rem,* pmod
896 movl %ecx, 4(%edi) / rem,
897 movl (%esp), %eax / r, r
898 movl 4(%esp), %edx / r, r
899 je .LL72
900 negl %eax / r
901 adcl $0, %edx /, r
902 negl %edx / r
903 .LL72:
904 addl $24, %esp
905 popl %esi
906 popl %edi
907 popl %ebp
909 .align 16
910 .LL73:
911 negl %eax
912 adcl $0, %edx
913 movl 44(%esp), %esi / y,
914 negl %edx
915 testl %esi, %esi
916 movl %edx, 12(%esp) /, xt
917 movl %eax, 8(%esp) /, xt
918 movl $1, %ebp /, negative
919 movl 40(%esp), %edx / y, yt
920 movl 44(%esp), %ecx / y, yt
921 jns .LL70
922 .align 16
923 .LL74:
924 negl %edx / yt
925 adcl $0, %ecx /, yt
926 negl %ecx / yt
927 xorl $1, %ebp /, negative
928 jmp .LL70
929 .align 16
930 .LL75:
931 negl %edx / rem
932 adcl $0, %ecx /, rem
933 negl %ecx / rem
934 jmp .LL71
935 SET_SIZE(SDivRem)
938 * __divrem64
940 * Perform division of two signed 64-bit quantities, returning the
941 * quotient in %edx:%eax, and the remainder in %ecx:%esi. __divrem64
942 * pops the arguments on return.
944 ENTRY(__divrem64)
945 subl $20, %esp
946 movl %esp, %ecx /, tmp64
947 movl 24(%esp), %eax / x, x
948 movl 28(%esp), %edx / x, x
949 pushl %ecx / tmp64
950 pushl 40(%esp) / y
951 pushl 40(%esp)
952 call SDivRem
953 movl 16(%esp), %ecx
954 movl 12(%esp),%esi / rem
955 addl $32, %esp
956 ret $16
957 SET_SIZE(__divrem64)