17c478bd9Sstevel@tonic-gate/* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*9a70fc3bSMark J. Nelson * Common Development and Distribution License (the "License"). 6*9a70fc3bSMark J. Nelson * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate/* 227c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 26*9a70fc3bSMark J. Nelson .file "_div64.s" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate#include "SYS.h" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate/* 317c478bd9Sstevel@tonic-gate * C support for 64-bit modulo and division. 327c478bd9Sstevel@tonic-gate * Hand-customized compiler output - see comments for details. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate/* 367c478bd9Sstevel@tonic-gate * int32_t/int64_t division/manipulation 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * Hand-customized compiler output: the non-GCC entry points depart from 397c478bd9Sstevel@tonic-gate * the SYS V ABI by requiring their arguments to be popped, and in the 407c478bd9Sstevel@tonic-gate * [u]divrem64 cases returning the remainder in %ecx:%esi. Note the 417c478bd9Sstevel@tonic-gate * compiler-generated use of %edx:%eax for the first argument of 427c478bd9Sstevel@tonic-gate * internal entry points. 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * Inlines for speed: 457c478bd9Sstevel@tonic-gate * - counting the number of leading zeros in a word 467c478bd9Sstevel@tonic-gate * - multiplying two 32-bit numbers giving a 64-bit result 477c478bd9Sstevel@tonic-gate * - dividing a 64-bit number by a 32-bit number, giving both quotient 487c478bd9Sstevel@tonic-gate * and remainder 497c478bd9Sstevel@tonic-gate * - subtracting two 64-bit results 507c478bd9Sstevel@tonic-gate */ 517c478bd9Sstevel@tonic-gate/ #define LO(X) ((uint32_t)(X) & 0xffffffff) 527c478bd9Sstevel@tonic-gate/ #define HI(X) ((uint32_t)((X) >> 32) & 0xffffffff) 537c478bd9Sstevel@tonic-gate/ #define HILO(H, L) (((uint64_t)(H) << 32) + (L)) 547c478bd9Sstevel@tonic-gate/ 557c478bd9Sstevel@tonic-gate/ /* give index of highest bit */ 567c478bd9Sstevel@tonic-gate/ #define HIBIT(a, r) \ 577c478bd9Sstevel@tonic-gate/ asm("bsrl %1,%0": "=r"((uint32_t)(r)) : "g" (a)) 587c478bd9Sstevel@tonic-gate/ 597c478bd9Sstevel@tonic-gate/ /* multiply two uint32_ts resulting in a uint64_t */ 607c478bd9Sstevel@tonic-gate/ #define A_MUL32(a, b, lo, hi) \ 617c478bd9Sstevel@tonic-gate/ asm("mull %2" \ 627c478bd9Sstevel@tonic-gate/ : "=a"((uint32_t)(lo)), "=d"((uint32_t)(hi)) : "g" (b), "0"(a)) 637c478bd9Sstevel@tonic-gate/ 647c478bd9Sstevel@tonic-gate/ /* divide a uint64_t by a uint32_t */ 657c478bd9Sstevel@tonic-gate/ #define A_DIV32(lo, hi, b, q, r) \ 667c478bd9Sstevel@tonic-gate/ asm("divl %2" \ 677c478bd9Sstevel@tonic-gate/ : "=a"((uint32_t)(q)), "=d"((uint32_t)(r)) \ 687c478bd9Sstevel@tonic-gate/ : "g" (b), "0"((uint32_t)(lo)), "1"((uint32_t)hi)) 697c478bd9Sstevel@tonic-gate/ 707c478bd9Sstevel@tonic-gate/ /* subtract two uint64_ts (with borrow) */ 717c478bd9Sstevel@tonic-gate/ #define A_SUB2(bl, bh, al, ah) \ 727c478bd9Sstevel@tonic-gate/ asm("subl %4,%0\n\tsbbl %5,%1" \ 737c478bd9Sstevel@tonic-gate/ : "=&r"((uint32_t)(al)), "=r"((uint32_t)(ah)) \ 747c478bd9Sstevel@tonic-gate/ : "0"((uint32_t)(al)), "1"((uint32_t)(ah)), "g"((uint32_t)(bl)), \ 757c478bd9Sstevel@tonic-gate/ "g"((uint32_t)(bh))) 767c478bd9Sstevel@tonic-gate/ 777c478bd9Sstevel@tonic-gate/ /* 787c478bd9Sstevel@tonic-gate/ * Unsigned division with remainder. 797c478bd9Sstevel@tonic-gate/ * Divide two uint64_ts, and calculate remainder. 807c478bd9Sstevel@tonic-gate/ */ 817c478bd9Sstevel@tonic-gate/ uint64_t 827c478bd9Sstevel@tonic-gate/ UDivRem(uint64_t x, uint64_t y, uint64_t * pmod) 837c478bd9Sstevel@tonic-gate/ { 847c478bd9Sstevel@tonic-gate/ /* simple cases: y is a single uint32_t */ 857c478bd9Sstevel@tonic-gate/ if (HI(y) == 0) { 867c478bd9Sstevel@tonic-gate/ uint32_t div_hi, div_rem; 877c478bd9Sstevel@tonic-gate/ uint32_t q0, q1; 887c478bd9Sstevel@tonic-gate/ 897c478bd9Sstevel@tonic-gate/ /* calculate q1 */ 907c478bd9Sstevel@tonic-gate/ if (HI(x) < LO(y)) { 917c478bd9Sstevel@tonic-gate/ /* result is a single uint32_t, use one division */ 927c478bd9Sstevel@tonic-gate/ q1 = 0; 937c478bd9Sstevel@tonic-gate/ div_hi = HI(x); 947c478bd9Sstevel@tonic-gate/ } else { 957c478bd9Sstevel@tonic-gate/ /* result is a double uint32_t, use two divisions */ 967c478bd9Sstevel@tonic-gate/ A_DIV32(HI(x), 0, LO(y), q1, div_hi); 977c478bd9Sstevel@tonic-gate/ } 987c478bd9Sstevel@tonic-gate/ 997c478bd9Sstevel@tonic-gate/ /* calculate q0 and remainder */ 1007c478bd9Sstevel@tonic-gate/ A_DIV32(LO(x), div_hi, LO(y), q0, div_rem); 1017c478bd9Sstevel@tonic-gate/ 1027c478bd9Sstevel@tonic-gate/ /* return remainder */ 1037c478bd9Sstevel@tonic-gate/ *pmod = div_rem; 1047c478bd9Sstevel@tonic-gate/ 1057c478bd9Sstevel@tonic-gate/ /* return result */ 1067c478bd9Sstevel@tonic-gate/ return (HILO(q1, q0)); 1077c478bd9Sstevel@tonic-gate/ 1087c478bd9Sstevel@tonic-gate/ } else if (HI(x) < HI(y)) { 1097c478bd9Sstevel@tonic-gate/ /* HI(x) < HI(y) => x < y => result is 0 */ 1107c478bd9Sstevel@tonic-gate/ 1117c478bd9Sstevel@tonic-gate/ /* return remainder */ 1127c478bd9Sstevel@tonic-gate/ *pmod = x; 1137c478bd9Sstevel@tonic-gate/ 1147c478bd9Sstevel@tonic-gate/ /* return result */ 1157c478bd9Sstevel@tonic-gate/ return (0); 1167c478bd9Sstevel@tonic-gate/ 1177c478bd9Sstevel@tonic-gate/ } else { 1187c478bd9Sstevel@tonic-gate/ /* 1197c478bd9Sstevel@tonic-gate/ * uint64_t by uint64_t division, resulting in a one-uint32_t 1207c478bd9Sstevel@tonic-gate/ * result 1217c478bd9Sstevel@tonic-gate/ */ 1227c478bd9Sstevel@tonic-gate/ uint32_t y0, y1; 1237c478bd9Sstevel@tonic-gate/ uint32_t x1, x0; 1247c478bd9Sstevel@tonic-gate/ uint32_t q0; 1257c478bd9Sstevel@tonic-gate/ uint32_t normshift; 1267c478bd9Sstevel@tonic-gate/ 1277c478bd9Sstevel@tonic-gate/ /* normalize by shifting x and y so MSB(y) == 1 */ 1287c478bd9Sstevel@tonic-gate/ HIBIT(HI(y), normshift); /* index of highest 1 bit */ 1297c478bd9Sstevel@tonic-gate/ normshift = 31 - normshift; 1307c478bd9Sstevel@tonic-gate/ 1317c478bd9Sstevel@tonic-gate/ if (normshift == 0) { 1327c478bd9Sstevel@tonic-gate/ /* no shifting needed, and x < 2*y so q <= 1 */ 1337c478bd9Sstevel@tonic-gate/ y1 = HI(y); 1347c478bd9Sstevel@tonic-gate/ y0 = LO(y); 1357c478bd9Sstevel@tonic-gate/ x1 = HI(x); 1367c478bd9Sstevel@tonic-gate/ x0 = LO(x); 1377c478bd9Sstevel@tonic-gate/ 1387c478bd9Sstevel@tonic-gate/ /* if x >= y then q = 1 (note x1 >= y1) */ 1397c478bd9Sstevel@tonic-gate/ if (x1 > y1 || x0 >= y0) { 1407c478bd9Sstevel@tonic-gate/ q0 = 1; 1417c478bd9Sstevel@tonic-gate/ /* subtract y from x to get remainder */ 1427c478bd9Sstevel@tonic-gate/ A_SUB2(y0, y1, x0, x1); 1437c478bd9Sstevel@tonic-gate/ } else { 1447c478bd9Sstevel@tonic-gate/ q0 = 0; 1457c478bd9Sstevel@tonic-gate/ } 1467c478bd9Sstevel@tonic-gate/ 1477c478bd9Sstevel@tonic-gate/ /* return remainder */ 1487c478bd9Sstevel@tonic-gate/ *pmod = HILO(x1, x0); 1497c478bd9Sstevel@tonic-gate/ 1507c478bd9Sstevel@tonic-gate/ /* return result */ 1517c478bd9Sstevel@tonic-gate/ return (q0); 1527c478bd9Sstevel@tonic-gate/ 1537c478bd9Sstevel@tonic-gate/ } else { 1547c478bd9Sstevel@tonic-gate/ /* 1557c478bd9Sstevel@tonic-gate/ * the last case: result is one uint32_t, but we need to 1567c478bd9Sstevel@tonic-gate/ * normalize 1577c478bd9Sstevel@tonic-gate/ */ 1587c478bd9Sstevel@tonic-gate/ uint64_t dt; 1597c478bd9Sstevel@tonic-gate/ uint32_t t0, t1, x2; 1607c478bd9Sstevel@tonic-gate/ 1617c478bd9Sstevel@tonic-gate/ /* normalize y */ 1627c478bd9Sstevel@tonic-gate/ dt = (y << normshift); 1637c478bd9Sstevel@tonic-gate/ y1 = HI(dt); 1647c478bd9Sstevel@tonic-gate/ y0 = LO(dt); 1657c478bd9Sstevel@tonic-gate/ 1667c478bd9Sstevel@tonic-gate/ /* normalize x (we need 3 uint32_ts!!!) */ 1677c478bd9Sstevel@tonic-gate/ x2 = (HI(x) >> (32 - normshift)); 1687c478bd9Sstevel@tonic-gate/ dt = (x << normshift); 1697c478bd9Sstevel@tonic-gate/ x1 = HI(dt); 1707c478bd9Sstevel@tonic-gate/ x0 = LO(dt); 1717c478bd9Sstevel@tonic-gate/ 1727c478bd9Sstevel@tonic-gate/ /* estimate q0, and reduce x to a two uint32_t value */ 1737c478bd9Sstevel@tonic-gate/ A_DIV32(x1, x2, y1, q0, x1); 1747c478bd9Sstevel@tonic-gate/ 1757c478bd9Sstevel@tonic-gate/ /* adjust q0 down if too high */ 1767c478bd9Sstevel@tonic-gate/ /* 1777c478bd9Sstevel@tonic-gate/ * because of the limited range of x2 we can only be 1787c478bd9Sstevel@tonic-gate/ * one off 1797c478bd9Sstevel@tonic-gate/ */ 1807c478bd9Sstevel@tonic-gate/ A_MUL32(y0, q0, t0, t1); 1817c478bd9Sstevel@tonic-gate/ if (t1 > x1 || (t1 == x1 && t0 > x0)) { 1827c478bd9Sstevel@tonic-gate/ q0--; 1837c478bd9Sstevel@tonic-gate/ A_SUB2(y0, y1, t0, t1); 1847c478bd9Sstevel@tonic-gate/ } 1857c478bd9Sstevel@tonic-gate/ /* return remainder */ 1867c478bd9Sstevel@tonic-gate/ /* subtract product from x to get remainder */ 1877c478bd9Sstevel@tonic-gate/ A_SUB2(t0, t1, x0, x1); 1887c478bd9Sstevel@tonic-gate/ *pmod = (HILO(x1, x0) >> normshift); 1897c478bd9Sstevel@tonic-gate/ 1907c478bd9Sstevel@tonic-gate/ /* return result */ 1917c478bd9Sstevel@tonic-gate/ return (q0); 1927c478bd9Sstevel@tonic-gate/ } 1937c478bd9Sstevel@tonic-gate/ } 1947c478bd9Sstevel@tonic-gate/ } 1957c478bd9Sstevel@tonic-gate ENTRY(UDivRem) 1967c478bd9Sstevel@tonic-gate pushl %ebp 1977c478bd9Sstevel@tonic-gate pushl %edi 1987c478bd9Sstevel@tonic-gate pushl %esi 1997c478bd9Sstevel@tonic-gate subl $48, %esp 2007c478bd9Sstevel@tonic-gate movl 68(%esp), %edi / y, 2017c478bd9Sstevel@tonic-gate testl %edi, %edi / tmp63 2027c478bd9Sstevel@tonic-gate movl %eax, 40(%esp) / x, x 2037c478bd9Sstevel@tonic-gate movl %edx, 44(%esp) / x, x 2047c478bd9Sstevel@tonic-gate movl %edi, %esi /, tmp62 2057c478bd9Sstevel@tonic-gate movl %edi, %ecx / tmp62, tmp63 2067c478bd9Sstevel@tonic-gate jne .LL2 2077c478bd9Sstevel@tonic-gate movl %edx, %eax /, tmp68 2087c478bd9Sstevel@tonic-gate cmpl 64(%esp), %eax / y, tmp68 2097c478bd9Sstevel@tonic-gate jae .LL21 2107c478bd9Sstevel@tonic-gate.LL4: 2117c478bd9Sstevel@tonic-gate movl 72(%esp), %ebp / pmod, 2127c478bd9Sstevel@tonic-gate xorl %esi, %esi / <result> 2137c478bd9Sstevel@tonic-gate movl 40(%esp), %eax / x, q0 2147c478bd9Sstevel@tonic-gate movl %ecx, %edi / <result>, <result> 2157c478bd9Sstevel@tonic-gate divl 64(%esp) / y 2167c478bd9Sstevel@tonic-gate movl %edx, (%ebp) / div_rem, 2177c478bd9Sstevel@tonic-gate xorl %edx, %edx / q0 2187c478bd9Sstevel@tonic-gate addl %eax, %esi / q0, <result> 2197c478bd9Sstevel@tonic-gate movl $0, 4(%ebp) 2207c478bd9Sstevel@tonic-gate adcl %edx, %edi / q0, <result> 2217c478bd9Sstevel@tonic-gate addl $48, %esp 2227c478bd9Sstevel@tonic-gate movl %esi, %eax / <result>, <result> 2237c478bd9Sstevel@tonic-gate popl %esi 2247c478bd9Sstevel@tonic-gate movl %edi, %edx / <result>, <result> 2257c478bd9Sstevel@tonic-gate popl %edi 2267c478bd9Sstevel@tonic-gate popl %ebp 2277c478bd9Sstevel@tonic-gate ret 2287c478bd9Sstevel@tonic-gate .align 16 2297c478bd9Sstevel@tonic-gate.LL2: 2307c478bd9Sstevel@tonic-gate movl 44(%esp), %eax / x, 2317c478bd9Sstevel@tonic-gate xorl %edx, %edx 2327c478bd9Sstevel@tonic-gate cmpl %esi, %eax / tmp62, tmp5 2337c478bd9Sstevel@tonic-gate movl %eax, 32(%esp) / tmp5, 2347c478bd9Sstevel@tonic-gate movl %edx, 36(%esp) 2357c478bd9Sstevel@tonic-gate jae .LL6 2367c478bd9Sstevel@tonic-gate movl 72(%esp), %esi / pmod, 2377c478bd9Sstevel@tonic-gate movl 40(%esp), %ebp / x, 2387c478bd9Sstevel@tonic-gate movl 44(%esp), %ecx / x, 2397c478bd9Sstevel@tonic-gate movl %ebp, (%esi) 2407c478bd9Sstevel@tonic-gate movl %ecx, 4(%esi) 2417c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 2427c478bd9Sstevel@tonic-gate xorl %esi, %esi / <result> 2437c478bd9Sstevel@tonic-gate.LL22: 2447c478bd9Sstevel@tonic-gate addl $48, %esp 2457c478bd9Sstevel@tonic-gate movl %esi, %eax / <result>, <result> 2467c478bd9Sstevel@tonic-gate popl %esi 2477c478bd9Sstevel@tonic-gate movl %edi, %edx / <result>, <result> 2487c478bd9Sstevel@tonic-gate popl %edi 2497c478bd9Sstevel@tonic-gate popl %ebp 2507c478bd9Sstevel@tonic-gate ret 2517c478bd9Sstevel@tonic-gate .align 16 2527c478bd9Sstevel@tonic-gate.LL21: 2537c478bd9Sstevel@tonic-gate movl %edi, %edx / tmp63, div_hi 2547c478bd9Sstevel@tonic-gate divl 64(%esp) / y 2557c478bd9Sstevel@tonic-gate movl %eax, %ecx /, q1 2567c478bd9Sstevel@tonic-gate jmp .LL4 2577c478bd9Sstevel@tonic-gate .align 16 2587c478bd9Sstevel@tonic-gate.LL6: 2597c478bd9Sstevel@tonic-gate movl $31, %edi /, tmp87 2607c478bd9Sstevel@tonic-gate bsrl %esi,%edx / tmp62, normshift 2617c478bd9Sstevel@tonic-gate subl %edx, %edi / normshift, tmp87 2627c478bd9Sstevel@tonic-gate movl %edi, 28(%esp) / tmp87, 2637c478bd9Sstevel@tonic-gate jne .LL8 2647c478bd9Sstevel@tonic-gate movl 32(%esp), %edx /, x1 2657c478bd9Sstevel@tonic-gate cmpl %ecx, %edx / y1, x1 2667c478bd9Sstevel@tonic-gate movl 64(%esp), %edi / y, y0 2677c478bd9Sstevel@tonic-gate movl 40(%esp), %esi / x, x0 2687c478bd9Sstevel@tonic-gate ja .LL10 2697c478bd9Sstevel@tonic-gate xorl %ebp, %ebp / q0 2707c478bd9Sstevel@tonic-gate cmpl %edi, %esi / y0, x0 2717c478bd9Sstevel@tonic-gate jb .LL11 2727c478bd9Sstevel@tonic-gate.LL10: 2737c478bd9Sstevel@tonic-gate movl $1, %ebp /, q0 2747c478bd9Sstevel@tonic-gate subl %edi,%esi / y0, x0 2757c478bd9Sstevel@tonic-gate sbbl %ecx,%edx / tmp63, x1 2767c478bd9Sstevel@tonic-gate.LL11: 2777c478bd9Sstevel@tonic-gate movl %edx, %ecx / x1, x1 2787c478bd9Sstevel@tonic-gate xorl %edx, %edx / x1 2797c478bd9Sstevel@tonic-gate xorl %edi, %edi / x0 2807c478bd9Sstevel@tonic-gate addl %esi, %edx / x0, x1 2817c478bd9Sstevel@tonic-gate adcl %edi, %ecx / x0, x1 2827c478bd9Sstevel@tonic-gate movl 72(%esp), %esi / pmod, 2837c478bd9Sstevel@tonic-gate movl %edx, (%esi) / x1, 2847c478bd9Sstevel@tonic-gate movl %ecx, 4(%esi) / x1, 2857c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 2867c478bd9Sstevel@tonic-gate movl %ebp, %esi / q0, <result> 2877c478bd9Sstevel@tonic-gate jmp .LL22 2887c478bd9Sstevel@tonic-gate .align 16 2897c478bd9Sstevel@tonic-gate.LL8: 2907c478bd9Sstevel@tonic-gate movb 28(%esp), %cl 2917c478bd9Sstevel@tonic-gate movl 64(%esp), %esi / y, dt 2927c478bd9Sstevel@tonic-gate movl 68(%esp), %edi / y, dt 2937c478bd9Sstevel@tonic-gate shldl %esi, %edi /, dt, dt 2947c478bd9Sstevel@tonic-gate sall %cl, %esi /, dt 2957c478bd9Sstevel@tonic-gate andl $32, %ecx 2967c478bd9Sstevel@tonic-gate jne .LL23 2977c478bd9Sstevel@tonic-gate.LL17: 2987c478bd9Sstevel@tonic-gate movl $32, %ecx /, tmp102 2997c478bd9Sstevel@tonic-gate subl 28(%esp), %ecx /, tmp102 3007c478bd9Sstevel@tonic-gate movl %esi, %ebp / dt, y0 3017c478bd9Sstevel@tonic-gate movl 32(%esp), %esi 3027c478bd9Sstevel@tonic-gate shrl %cl, %esi / tmp102, 3037c478bd9Sstevel@tonic-gate movl %edi, 24(%esp) / tmp99, 3047c478bd9Sstevel@tonic-gate movb 28(%esp), %cl 3057c478bd9Sstevel@tonic-gate movl %esi, 12(%esp) /, x2 3067c478bd9Sstevel@tonic-gate movl 44(%esp), %edi / x, dt 3077c478bd9Sstevel@tonic-gate movl 40(%esp), %esi / x, dt 3087c478bd9Sstevel@tonic-gate shldl %esi, %edi /, dt, dt 3097c478bd9Sstevel@tonic-gate sall %cl, %esi /, dt 3107c478bd9Sstevel@tonic-gate andl $32, %ecx 3117c478bd9Sstevel@tonic-gate je .LL18 3127c478bd9Sstevel@tonic-gate movl %esi, %edi / dt, dt 3137c478bd9Sstevel@tonic-gate xorl %esi, %esi / dt 3147c478bd9Sstevel@tonic-gate.LL18: 3157c478bd9Sstevel@tonic-gate movl %edi, %ecx / dt, 3167c478bd9Sstevel@tonic-gate movl %edi, %eax / tmp2, 3177c478bd9Sstevel@tonic-gate movl %ecx, (%esp) 3187c478bd9Sstevel@tonic-gate movl 12(%esp), %edx / x2, 3197c478bd9Sstevel@tonic-gate divl 24(%esp) 3207c478bd9Sstevel@tonic-gate movl %edx, %ecx /, x1 3217c478bd9Sstevel@tonic-gate xorl %edi, %edi 3227c478bd9Sstevel@tonic-gate movl %eax, 20(%esp) 3237c478bd9Sstevel@tonic-gate movl %ebp, %eax / y0, t0 3247c478bd9Sstevel@tonic-gate mull 20(%esp) 3257c478bd9Sstevel@tonic-gate cmpl %ecx, %edx / x1, t1 3267c478bd9Sstevel@tonic-gate movl %edi, 4(%esp) 3277c478bd9Sstevel@tonic-gate ja .LL14 3287c478bd9Sstevel@tonic-gate je .LL24 3297c478bd9Sstevel@tonic-gate.LL15: 3307c478bd9Sstevel@tonic-gate movl %ecx, %edi / x1, 3317c478bd9Sstevel@tonic-gate subl %eax,%esi / t0, x0 3327c478bd9Sstevel@tonic-gate sbbl %edx,%edi / t1, 3337c478bd9Sstevel@tonic-gate movl %edi, %eax /, x1 3347c478bd9Sstevel@tonic-gate movl %eax, %edx / x1, x1 3357c478bd9Sstevel@tonic-gate xorl %eax, %eax / x1 3367c478bd9Sstevel@tonic-gate xorl %ebp, %ebp / x0 3377c478bd9Sstevel@tonic-gate addl %esi, %eax / x0, x1 3387c478bd9Sstevel@tonic-gate adcl %ebp, %edx / x0, x1 3397c478bd9Sstevel@tonic-gate movb 28(%esp), %cl 3407c478bd9Sstevel@tonic-gate shrdl %edx, %eax /, x1, x1 3417c478bd9Sstevel@tonic-gate shrl %cl, %edx /, x1 3427c478bd9Sstevel@tonic-gate andl $32, %ecx 3437c478bd9Sstevel@tonic-gate je .LL16 3447c478bd9Sstevel@tonic-gate movl %edx, %eax / x1, x1 3457c478bd9Sstevel@tonic-gate xorl %edx, %edx / x1 3467c478bd9Sstevel@tonic-gate.LL16: 3477c478bd9Sstevel@tonic-gate movl 72(%esp), %ecx / pmod, 3487c478bd9Sstevel@tonic-gate movl 20(%esp), %esi /, <result> 3497c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 3507c478bd9Sstevel@tonic-gate movl %eax, (%ecx) / x1, 3517c478bd9Sstevel@tonic-gate movl %edx, 4(%ecx) / x1, 3527c478bd9Sstevel@tonic-gate jmp .LL22 3537c478bd9Sstevel@tonic-gate .align 16 3547c478bd9Sstevel@tonic-gate.LL24: 3557c478bd9Sstevel@tonic-gate cmpl %esi, %eax / x0, t0 3567c478bd9Sstevel@tonic-gate jbe .LL15 3577c478bd9Sstevel@tonic-gate.LL14: 3587c478bd9Sstevel@tonic-gate decl 20(%esp) 3597c478bd9Sstevel@tonic-gate subl %ebp,%eax / y0, t0 3607c478bd9Sstevel@tonic-gate sbbl 24(%esp),%edx /, t1 3617c478bd9Sstevel@tonic-gate jmp .LL15 3627c478bd9Sstevel@tonic-gate.LL23: 3637c478bd9Sstevel@tonic-gate movl %esi, %edi / dt, dt 3647c478bd9Sstevel@tonic-gate xorl %esi, %esi / dt 3657c478bd9Sstevel@tonic-gate jmp .LL17 3667c478bd9Sstevel@tonic-gate SET_SIZE(UDivRem) 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate/* 3697c478bd9Sstevel@tonic-gate * Unsigned division without remainder. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate/ uint64_t 3727c478bd9Sstevel@tonic-gate/ UDiv(uint64_t x, uint64_t y) 3737c478bd9Sstevel@tonic-gate/ { 3747c478bd9Sstevel@tonic-gate/ if (HI(y) == 0) { 3757c478bd9Sstevel@tonic-gate/ /* simple cases: y is a single uint32_t */ 3767c478bd9Sstevel@tonic-gate/ uint32_t div_hi, div_rem; 3777c478bd9Sstevel@tonic-gate/ uint32_t q0, q1; 3787c478bd9Sstevel@tonic-gate/ 3797c478bd9Sstevel@tonic-gate/ /* calculate q1 */ 3807c478bd9Sstevel@tonic-gate/ if (HI(x) < LO(y)) { 3817c478bd9Sstevel@tonic-gate/ /* result is a single uint32_t, use one division */ 3827c478bd9Sstevel@tonic-gate/ q1 = 0; 3837c478bd9Sstevel@tonic-gate/ div_hi = HI(x); 3847c478bd9Sstevel@tonic-gate/ } else { 3857c478bd9Sstevel@tonic-gate/ /* result is a double uint32_t, use two divisions */ 3867c478bd9Sstevel@tonic-gate/ A_DIV32(HI(x), 0, LO(y), q1, div_hi); 3877c478bd9Sstevel@tonic-gate/ } 3887c478bd9Sstevel@tonic-gate/ 3897c478bd9Sstevel@tonic-gate/ /* calculate q0 and remainder */ 3907c478bd9Sstevel@tonic-gate/ A_DIV32(LO(x), div_hi, LO(y), q0, div_rem); 3917c478bd9Sstevel@tonic-gate/ 3927c478bd9Sstevel@tonic-gate/ /* return result */ 3937c478bd9Sstevel@tonic-gate/ return (HILO(q1, q0)); 3947c478bd9Sstevel@tonic-gate/ 3957c478bd9Sstevel@tonic-gate/ } else if (HI(x) < HI(y)) { 3967c478bd9Sstevel@tonic-gate/ /* HI(x) < HI(y) => x < y => result is 0 */ 3977c478bd9Sstevel@tonic-gate/ 3987c478bd9Sstevel@tonic-gate/ /* return result */ 3997c478bd9Sstevel@tonic-gate/ return (0); 4007c478bd9Sstevel@tonic-gate/ 4017c478bd9Sstevel@tonic-gate/ } else { 4027c478bd9Sstevel@tonic-gate/ /* 4037c478bd9Sstevel@tonic-gate/ * uint64_t by uint64_t division, resulting in a one-uint32_t 4047c478bd9Sstevel@tonic-gate/ * result 4057c478bd9Sstevel@tonic-gate/ */ 4067c478bd9Sstevel@tonic-gate/ uint32_t y0, y1; 4077c478bd9Sstevel@tonic-gate/ uint32_t x1, x0; 4087c478bd9Sstevel@tonic-gate/ uint32_t q0; 4097c478bd9Sstevel@tonic-gate/ unsigned normshift; 4107c478bd9Sstevel@tonic-gate/ 4117c478bd9Sstevel@tonic-gate/ /* normalize by shifting x and y so MSB(y) == 1 */ 4127c478bd9Sstevel@tonic-gate/ HIBIT(HI(y), normshift); /* index of highest 1 bit */ 4137c478bd9Sstevel@tonic-gate/ normshift = 31 - normshift; 4147c478bd9Sstevel@tonic-gate/ 4157c478bd9Sstevel@tonic-gate/ if (normshift == 0) { 4167c478bd9Sstevel@tonic-gate/ /* no shifting needed, and x < 2*y so q <= 1 */ 4177c478bd9Sstevel@tonic-gate/ y1 = HI(y); 4187c478bd9Sstevel@tonic-gate/ y0 = LO(y); 4197c478bd9Sstevel@tonic-gate/ x1 = HI(x); 4207c478bd9Sstevel@tonic-gate/ x0 = LO(x); 4217c478bd9Sstevel@tonic-gate/ 4227c478bd9Sstevel@tonic-gate/ /* if x >= y then q = 1 (note x1 >= y1) */ 4237c478bd9Sstevel@tonic-gate/ if (x1 > y1 || x0 >= y0) { 4247c478bd9Sstevel@tonic-gate/ q0 = 1; 4257c478bd9Sstevel@tonic-gate/ /* subtract y from x to get remainder */ 4267c478bd9Sstevel@tonic-gate/ /* A_SUB2(y0, y1, x0, x1); */ 4277c478bd9Sstevel@tonic-gate/ } else { 4287c478bd9Sstevel@tonic-gate/ q0 = 0; 4297c478bd9Sstevel@tonic-gate/ } 4307c478bd9Sstevel@tonic-gate/ 4317c478bd9Sstevel@tonic-gate/ /* return result */ 4327c478bd9Sstevel@tonic-gate/ return (q0); 4337c478bd9Sstevel@tonic-gate/ 4347c478bd9Sstevel@tonic-gate/ } else { 4357c478bd9Sstevel@tonic-gate/ /* 4367c478bd9Sstevel@tonic-gate/ * the last case: result is one uint32_t, but we need to 4377c478bd9Sstevel@tonic-gate/ * normalize 4387c478bd9Sstevel@tonic-gate/ */ 4397c478bd9Sstevel@tonic-gate/ uint64_t dt; 4407c478bd9Sstevel@tonic-gate/ uint32_t t0, t1, x2; 4417c478bd9Sstevel@tonic-gate/ 4427c478bd9Sstevel@tonic-gate/ /* normalize y */ 4437c478bd9Sstevel@tonic-gate/ dt = (y << normshift); 4447c478bd9Sstevel@tonic-gate/ y1 = HI(dt); 4457c478bd9Sstevel@tonic-gate/ y0 = LO(dt); 4467c478bd9Sstevel@tonic-gate/ 4477c478bd9Sstevel@tonic-gate/ /* normalize x (we need 3 uint32_ts!!!) */ 4487c478bd9Sstevel@tonic-gate/ x2 = (HI(x) >> (32 - normshift)); 4497c478bd9Sstevel@tonic-gate/ dt = (x << normshift); 4507c478bd9Sstevel@tonic-gate/ x1 = HI(dt); 4517c478bd9Sstevel@tonic-gate/ x0 = LO(dt); 4527c478bd9Sstevel@tonic-gate/ 4537c478bd9Sstevel@tonic-gate/ /* estimate q0, and reduce x to a two uint32_t value */ 4547c478bd9Sstevel@tonic-gate/ A_DIV32(x1, x2, y1, q0, x1); 4557c478bd9Sstevel@tonic-gate/ 4567c478bd9Sstevel@tonic-gate/ /* adjust q0 down if too high */ 4577c478bd9Sstevel@tonic-gate/ /* 4587c478bd9Sstevel@tonic-gate/ * because of the limited range of x2 we can only be 4597c478bd9Sstevel@tonic-gate/ * one off 4607c478bd9Sstevel@tonic-gate/ */ 4617c478bd9Sstevel@tonic-gate/ A_MUL32(y0, q0, t0, t1); 4627c478bd9Sstevel@tonic-gate/ if (t1 > x1 || (t1 == x1 && t0 > x0)) { 4637c478bd9Sstevel@tonic-gate/ q0--; 4647c478bd9Sstevel@tonic-gate/ } 4657c478bd9Sstevel@tonic-gate/ /* return result */ 4667c478bd9Sstevel@tonic-gate/ return (q0); 4677c478bd9Sstevel@tonic-gate/ } 4687c478bd9Sstevel@tonic-gate/ } 4697c478bd9Sstevel@tonic-gate/ } 4707c478bd9Sstevel@tonic-gate ENTRY(UDiv) 4717c478bd9Sstevel@tonic-gate pushl %ebp 4727c478bd9Sstevel@tonic-gate pushl %edi 4737c478bd9Sstevel@tonic-gate pushl %esi 4747c478bd9Sstevel@tonic-gate subl $40, %esp 4757c478bd9Sstevel@tonic-gate movl %edx, 36(%esp) / x, x 4767c478bd9Sstevel@tonic-gate movl 60(%esp), %edx / y, 4777c478bd9Sstevel@tonic-gate testl %edx, %edx / tmp62 4787c478bd9Sstevel@tonic-gate movl %eax, 32(%esp) / x, x 4797c478bd9Sstevel@tonic-gate movl %edx, %ecx / tmp61, tmp62 4807c478bd9Sstevel@tonic-gate movl %edx, %eax /, tmp61 4817c478bd9Sstevel@tonic-gate jne .LL26 4827c478bd9Sstevel@tonic-gate movl 36(%esp), %esi / x, 4837c478bd9Sstevel@tonic-gate cmpl 56(%esp), %esi / y, tmp67 4847c478bd9Sstevel@tonic-gate movl %esi, %eax /, tmp67 4857c478bd9Sstevel@tonic-gate movl %esi, %edx / tmp67, div_hi 4867c478bd9Sstevel@tonic-gate jb .LL28 4877c478bd9Sstevel@tonic-gate movl %ecx, %edx / tmp62, div_hi 4887c478bd9Sstevel@tonic-gate divl 56(%esp) / y 4897c478bd9Sstevel@tonic-gate movl %eax, %ecx /, q1 4907c478bd9Sstevel@tonic-gate.LL28: 4917c478bd9Sstevel@tonic-gate xorl %esi, %esi / <result> 4927c478bd9Sstevel@tonic-gate movl %ecx, %edi / <result>, <result> 4937c478bd9Sstevel@tonic-gate movl 32(%esp), %eax / x, q0 4947c478bd9Sstevel@tonic-gate xorl %ecx, %ecx / q0 4957c478bd9Sstevel@tonic-gate divl 56(%esp) / y 4967c478bd9Sstevel@tonic-gate addl %eax, %esi / q0, <result> 4977c478bd9Sstevel@tonic-gate adcl %ecx, %edi / q0, <result> 4987c478bd9Sstevel@tonic-gate.LL25: 4997c478bd9Sstevel@tonic-gate addl $40, %esp 5007c478bd9Sstevel@tonic-gate movl %esi, %eax / <result>, <result> 5017c478bd9Sstevel@tonic-gate popl %esi 5027c478bd9Sstevel@tonic-gate movl %edi, %edx / <result>, <result> 5037c478bd9Sstevel@tonic-gate popl %edi 5047c478bd9Sstevel@tonic-gate popl %ebp 5057c478bd9Sstevel@tonic-gate ret 5067c478bd9Sstevel@tonic-gate .align 16 5077c478bd9Sstevel@tonic-gate.LL26: 5087c478bd9Sstevel@tonic-gate movl 36(%esp), %esi / x, 5097c478bd9Sstevel@tonic-gate xorl %edi, %edi 5107c478bd9Sstevel@tonic-gate movl %esi, 24(%esp) / tmp1, 5117c478bd9Sstevel@tonic-gate movl %edi, 28(%esp) 5127c478bd9Sstevel@tonic-gate xorl %esi, %esi / <result> 5137c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 5147c478bd9Sstevel@tonic-gate cmpl %eax, 24(%esp) / tmp61, 5157c478bd9Sstevel@tonic-gate jb .LL25 5167c478bd9Sstevel@tonic-gate bsrl %eax,%ebp / tmp61, normshift 5177c478bd9Sstevel@tonic-gate movl $31, %eax /, tmp85 5187c478bd9Sstevel@tonic-gate subl %ebp, %eax / normshift, normshift 5197c478bd9Sstevel@tonic-gate jne .LL32 5207c478bd9Sstevel@tonic-gate movl 24(%esp), %eax /, x1 5217c478bd9Sstevel@tonic-gate cmpl %ecx, %eax / tmp62, x1 5227c478bd9Sstevel@tonic-gate movl 56(%esp), %esi / y, y0 5237c478bd9Sstevel@tonic-gate movl 32(%esp), %edx / x, x0 5247c478bd9Sstevel@tonic-gate ja .LL34 5257c478bd9Sstevel@tonic-gate xorl %eax, %eax / q0 5267c478bd9Sstevel@tonic-gate cmpl %esi, %edx / y0, x0 5277c478bd9Sstevel@tonic-gate jb .LL35 5287c478bd9Sstevel@tonic-gate.LL34: 5297c478bd9Sstevel@tonic-gate movl $1, %eax /, q0 5307c478bd9Sstevel@tonic-gate.LL35: 5317c478bd9Sstevel@tonic-gate movl %eax, %esi / q0, <result> 5327c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 5337c478bd9Sstevel@tonic-gate.LL45: 5347c478bd9Sstevel@tonic-gate addl $40, %esp 5357c478bd9Sstevel@tonic-gate movl %esi, %eax / <result>, <result> 5367c478bd9Sstevel@tonic-gate popl %esi 5377c478bd9Sstevel@tonic-gate movl %edi, %edx / <result>, <result> 5387c478bd9Sstevel@tonic-gate popl %edi 5397c478bd9Sstevel@tonic-gate popl %ebp 5407c478bd9Sstevel@tonic-gate ret 5417c478bd9Sstevel@tonic-gate .align 16 5427c478bd9Sstevel@tonic-gate.LL32: 5437c478bd9Sstevel@tonic-gate movb %al, %cl 5447c478bd9Sstevel@tonic-gate movl 56(%esp), %esi / y, 5457c478bd9Sstevel@tonic-gate movl 60(%esp), %edi / y, 5467c478bd9Sstevel@tonic-gate shldl %esi, %edi 5477c478bd9Sstevel@tonic-gate sall %cl, %esi 5487c478bd9Sstevel@tonic-gate andl $32, %ecx 5497c478bd9Sstevel@tonic-gate jne .LL43 5507c478bd9Sstevel@tonic-gate.LL40: 5517c478bd9Sstevel@tonic-gate movl $32, %ecx /, tmp96 5527c478bd9Sstevel@tonic-gate subl %eax, %ecx / normshift, tmp96 5537c478bd9Sstevel@tonic-gate movl %edi, %edx 5547c478bd9Sstevel@tonic-gate movl %edi, 20(%esp) /, dt 5557c478bd9Sstevel@tonic-gate movl 24(%esp), %ebp /, x2 5567c478bd9Sstevel@tonic-gate xorl %edi, %edi 5577c478bd9Sstevel@tonic-gate shrl %cl, %ebp / tmp96, x2 5587c478bd9Sstevel@tonic-gate movl %esi, 16(%esp) /, dt 5597c478bd9Sstevel@tonic-gate movb %al, %cl 5607c478bd9Sstevel@tonic-gate movl 32(%esp), %esi / x, dt 5617c478bd9Sstevel@tonic-gate movl %edi, 12(%esp) 5627c478bd9Sstevel@tonic-gate movl 36(%esp), %edi / x, dt 5637c478bd9Sstevel@tonic-gate shldl %esi, %edi /, dt, dt 5647c478bd9Sstevel@tonic-gate sall %cl, %esi /, dt 5657c478bd9Sstevel@tonic-gate andl $32, %ecx 5667c478bd9Sstevel@tonic-gate movl %edx, 8(%esp) 5677c478bd9Sstevel@tonic-gate je .LL41 5687c478bd9Sstevel@tonic-gate movl %esi, %edi / dt, dt 5697c478bd9Sstevel@tonic-gate xorl %esi, %esi / dt 5707c478bd9Sstevel@tonic-gate.LL41: 5717c478bd9Sstevel@tonic-gate xorl %ecx, %ecx 5727c478bd9Sstevel@tonic-gate movl %edi, %eax / tmp1, 5737c478bd9Sstevel@tonic-gate movl %ebp, %edx / x2, 5747c478bd9Sstevel@tonic-gate divl 8(%esp) 5757c478bd9Sstevel@tonic-gate movl %edx, %ebp /, x1 5767c478bd9Sstevel@tonic-gate movl %ecx, 4(%esp) 5777c478bd9Sstevel@tonic-gate movl %eax, %ecx /, q0 5787c478bd9Sstevel@tonic-gate movl 16(%esp), %eax / dt, 5797c478bd9Sstevel@tonic-gate mull %ecx / q0 5807c478bd9Sstevel@tonic-gate cmpl %ebp, %edx / x1, t1 5817c478bd9Sstevel@tonic-gate movl %edi, (%esp) 5827c478bd9Sstevel@tonic-gate movl %esi, %edi / dt, x0 5837c478bd9Sstevel@tonic-gate ja .LL38 5847c478bd9Sstevel@tonic-gate je .LL44 5857c478bd9Sstevel@tonic-gate.LL39: 5867c478bd9Sstevel@tonic-gate movl %ecx, %esi / q0, <result> 5877c478bd9Sstevel@tonic-gate.LL46: 5887c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 5897c478bd9Sstevel@tonic-gate jmp .LL45 5907c478bd9Sstevel@tonic-gate.LL44: 5917c478bd9Sstevel@tonic-gate cmpl %edi, %eax / x0, t0 5927c478bd9Sstevel@tonic-gate jbe .LL39 5937c478bd9Sstevel@tonic-gate.LL38: 5947c478bd9Sstevel@tonic-gate decl %ecx / q0 5957c478bd9Sstevel@tonic-gate movl %ecx, %esi / q0, <result> 5967c478bd9Sstevel@tonic-gate jmp .LL46 5977c478bd9Sstevel@tonic-gate.LL43: 5987c478bd9Sstevel@tonic-gate movl %esi, %edi 5997c478bd9Sstevel@tonic-gate xorl %esi, %esi 6007c478bd9Sstevel@tonic-gate jmp .LL40 6017c478bd9Sstevel@tonic-gate SET_SIZE(UDiv) 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate/* 6047c478bd9Sstevel@tonic-gate * __udiv64 6057c478bd9Sstevel@tonic-gate * 6067c478bd9Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the 6077c478bd9Sstevel@tonic-gate * quotient in %edx:%eax. __udiv64 pops the arguments on return, 6087c478bd9Sstevel@tonic-gate */ 6097c478bd9Sstevel@tonic-gate ENTRY(__udiv64) 6107c478bd9Sstevel@tonic-gate movl 4(%esp), %eax / x, x 6117c478bd9Sstevel@tonic-gate movl 8(%esp), %edx / x, x 6127c478bd9Sstevel@tonic-gate pushl 16(%esp) / y 6137c478bd9Sstevel@tonic-gate pushl 16(%esp) 6147c478bd9Sstevel@tonic-gate call UDiv 6157c478bd9Sstevel@tonic-gate addl $8, %esp 6167c478bd9Sstevel@tonic-gate ret $16 6177c478bd9Sstevel@tonic-gate SET_SIZE(__udiv64) 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate/* 6207c478bd9Sstevel@tonic-gate * __urem64 6217c478bd9Sstevel@tonic-gate * 6227c478bd9Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the 6237c478bd9Sstevel@tonic-gate * remainder in %edx:%eax. __urem64 pops the arguments on return 6247c478bd9Sstevel@tonic-gate */ 6257c478bd9Sstevel@tonic-gate ENTRY(__urem64) 6267c478bd9Sstevel@tonic-gate subl $12, %esp 6277c478bd9Sstevel@tonic-gate movl %esp, %ecx /, tmp65 6287c478bd9Sstevel@tonic-gate movl 16(%esp), %eax / x, x 6297c478bd9Sstevel@tonic-gate movl 20(%esp), %edx / x, x 6307c478bd9Sstevel@tonic-gate pushl %ecx / tmp65 6317c478bd9Sstevel@tonic-gate pushl 32(%esp) / y 6327c478bd9Sstevel@tonic-gate pushl 32(%esp) 6337c478bd9Sstevel@tonic-gate call UDivRem 6347c478bd9Sstevel@tonic-gate movl 12(%esp), %eax / rem, rem 6357c478bd9Sstevel@tonic-gate movl 16(%esp), %edx / rem, rem 6367c478bd9Sstevel@tonic-gate addl $24, %esp 6377c478bd9Sstevel@tonic-gate ret $16 6387c478bd9Sstevel@tonic-gate SET_SIZE(__urem64) 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate/* 6417c478bd9Sstevel@tonic-gate * __div64 6427c478bd9Sstevel@tonic-gate * 6437c478bd9Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the 6447c478bd9Sstevel@tonic-gate * quotient in %edx:%eax. __div64 pops the arguments on return. 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate/ int64_t 6477c478bd9Sstevel@tonic-gate/ __div64(int64_t x, int64_t y) 6487c478bd9Sstevel@tonic-gate/ { 6497c478bd9Sstevel@tonic-gate/ int negative; 6507c478bd9Sstevel@tonic-gate/ uint64_t xt, yt, r; 6517c478bd9Sstevel@tonic-gate/ 6527c478bd9Sstevel@tonic-gate/ if (x < 0) { 6537c478bd9Sstevel@tonic-gate/ xt = -(uint64_t) x; 6547c478bd9Sstevel@tonic-gate/ negative = 1; 6557c478bd9Sstevel@tonic-gate/ } else { 6567c478bd9Sstevel@tonic-gate/ xt = x; 6577c478bd9Sstevel@tonic-gate/ negative = 0; 6587c478bd9Sstevel@tonic-gate/ } 6597c478bd9Sstevel@tonic-gate/ if (y < 0) { 6607c478bd9Sstevel@tonic-gate/ yt = -(uint64_t) y; 6617c478bd9Sstevel@tonic-gate/ negative ^= 1; 6627c478bd9Sstevel@tonic-gate/ } else { 6637c478bd9Sstevel@tonic-gate/ yt = y; 6647c478bd9Sstevel@tonic-gate/ } 6657c478bd9Sstevel@tonic-gate/ r = UDiv(xt, yt); 6667c478bd9Sstevel@tonic-gate/ return (negative ? (int64_t) - r : r); 6677c478bd9Sstevel@tonic-gate/ } 6687c478bd9Sstevel@tonic-gate ENTRY(__div64) 6697c478bd9Sstevel@tonic-gate pushl %ebp 6707c478bd9Sstevel@tonic-gate pushl %edi 6717c478bd9Sstevel@tonic-gate pushl %esi 6727c478bd9Sstevel@tonic-gate subl $8, %esp 6737c478bd9Sstevel@tonic-gate movl 28(%esp), %edx / x, x 6747c478bd9Sstevel@tonic-gate testl %edx, %edx / x 6757c478bd9Sstevel@tonic-gate movl 24(%esp), %eax / x, x 6767c478bd9Sstevel@tonic-gate movl 32(%esp), %esi / y, y 6777c478bd9Sstevel@tonic-gate movl 36(%esp), %edi / y, y 6787c478bd9Sstevel@tonic-gate js .LL84 6797c478bd9Sstevel@tonic-gate xorl %ebp, %ebp / negative 6807c478bd9Sstevel@tonic-gate testl %edi, %edi / y 6817c478bd9Sstevel@tonic-gate movl %eax, (%esp) / x, xt 6827c478bd9Sstevel@tonic-gate movl %edx, 4(%esp) / x, xt 6837c478bd9Sstevel@tonic-gate movl %esi, %eax / y, yt 6847c478bd9Sstevel@tonic-gate movl %edi, %edx / y, yt 6857c478bd9Sstevel@tonic-gate js .LL85 6867c478bd9Sstevel@tonic-gate.LL82: 6877c478bd9Sstevel@tonic-gate pushl %edx / yt 6887c478bd9Sstevel@tonic-gate pushl %eax / yt 6897c478bd9Sstevel@tonic-gate movl 8(%esp), %eax / xt, xt 6907c478bd9Sstevel@tonic-gate movl 12(%esp), %edx / xt, xt 6917c478bd9Sstevel@tonic-gate call UDiv 6927c478bd9Sstevel@tonic-gate popl %ecx 6937c478bd9Sstevel@tonic-gate testl %ebp, %ebp / negative 6947c478bd9Sstevel@tonic-gate popl %esi 6957c478bd9Sstevel@tonic-gate je .LL83 6967c478bd9Sstevel@tonic-gate negl %eax / r 6977c478bd9Sstevel@tonic-gate adcl $0, %edx /, r 6987c478bd9Sstevel@tonic-gate negl %edx / r 6997c478bd9Sstevel@tonic-gate.LL83: 7007c478bd9Sstevel@tonic-gate addl $8, %esp 7017c478bd9Sstevel@tonic-gate popl %esi 7027c478bd9Sstevel@tonic-gate popl %edi 7037c478bd9Sstevel@tonic-gate popl %ebp 7047c478bd9Sstevel@tonic-gate ret $16 7057c478bd9Sstevel@tonic-gate .align 16 7067c478bd9Sstevel@tonic-gate.LL84: 7077c478bd9Sstevel@tonic-gate negl %eax / x 7087c478bd9Sstevel@tonic-gate adcl $0, %edx /, x 7097c478bd9Sstevel@tonic-gate negl %edx / x 7107c478bd9Sstevel@tonic-gate testl %edi, %edi / y 7117c478bd9Sstevel@tonic-gate movl %eax, (%esp) / x, xt 7127c478bd9Sstevel@tonic-gate movl %edx, 4(%esp) / x, xt 7137c478bd9Sstevel@tonic-gate movl $1, %ebp /, negative 7147c478bd9Sstevel@tonic-gate movl %esi, %eax / y, yt 7157c478bd9Sstevel@tonic-gate movl %edi, %edx / y, yt 7167c478bd9Sstevel@tonic-gate jns .LL82 7177c478bd9Sstevel@tonic-gate .align 16 7187c478bd9Sstevel@tonic-gate.LL85: 7197c478bd9Sstevel@tonic-gate negl %eax / yt 7207c478bd9Sstevel@tonic-gate adcl $0, %edx /, yt 7217c478bd9Sstevel@tonic-gate negl %edx / yt 7227c478bd9Sstevel@tonic-gate xorl $1, %ebp /, negative 7237c478bd9Sstevel@tonic-gate jmp .LL82 7247c478bd9Sstevel@tonic-gate SET_SIZE(__div64) 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate/* 7277c478bd9Sstevel@tonic-gate * __rem64 7287c478bd9Sstevel@tonic-gate * 7297c478bd9Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the 7307c478bd9Sstevel@tonic-gate * remainder in %edx:%eax. __rem64 pops the arguments on return. 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate/ int64_t 7337c478bd9Sstevel@tonic-gate/ __rem64(int64_t x, int64_t y) 7347c478bd9Sstevel@tonic-gate/ { 7357c478bd9Sstevel@tonic-gate/ uint64_t xt, yt, rem; 7367c478bd9Sstevel@tonic-gate/ 7377c478bd9Sstevel@tonic-gate/ if (x < 0) { 7387c478bd9Sstevel@tonic-gate/ xt = -(uint64_t) x; 7397c478bd9Sstevel@tonic-gate/ } else { 7407c478bd9Sstevel@tonic-gate/ xt = x; 7417c478bd9Sstevel@tonic-gate/ } 7427c478bd9Sstevel@tonic-gate/ if (y < 0) { 7437c478bd9Sstevel@tonic-gate/ yt = -(uint64_t) y; 7447c478bd9Sstevel@tonic-gate/ } else { 7457c478bd9Sstevel@tonic-gate/ yt = y; 7467c478bd9Sstevel@tonic-gate/ } 7477c478bd9Sstevel@tonic-gate/ (void) UDivRem(xt, yt, &rem); 7487c478bd9Sstevel@tonic-gate/ return (x < 0 ? (int64_t) - rem : rem); 7497c478bd9Sstevel@tonic-gate/ } 7507c478bd9Sstevel@tonic-gate ENTRY(__rem64) 7517c478bd9Sstevel@tonic-gate pushl %edi 7527c478bd9Sstevel@tonic-gate pushl %esi 7537c478bd9Sstevel@tonic-gate subl $20, %esp 7547c478bd9Sstevel@tonic-gate movl 36(%esp), %ecx / x, 7557c478bd9Sstevel@tonic-gate movl 32(%esp), %esi / x, 7567c478bd9Sstevel@tonic-gate movl 36(%esp), %edi / x, 7577c478bd9Sstevel@tonic-gate testl %ecx, %ecx 7587c478bd9Sstevel@tonic-gate movl 40(%esp), %eax / y, y 7597c478bd9Sstevel@tonic-gate movl 44(%esp), %edx / y, y 7607c478bd9Sstevel@tonic-gate movl %esi, (%esp) /, xt 7617c478bd9Sstevel@tonic-gate movl %edi, 4(%esp) /, xt 7627c478bd9Sstevel@tonic-gate js .LL92 7637c478bd9Sstevel@tonic-gate testl %edx, %edx / y 7647c478bd9Sstevel@tonic-gate movl %eax, %esi / y, yt 7657c478bd9Sstevel@tonic-gate movl %edx, %edi / y, yt 7667c478bd9Sstevel@tonic-gate js .LL93 7677c478bd9Sstevel@tonic-gate.LL90: 7687c478bd9Sstevel@tonic-gate leal 8(%esp), %eax /, tmp66 7697c478bd9Sstevel@tonic-gate pushl %eax / tmp66 7707c478bd9Sstevel@tonic-gate pushl %edi / yt 7717c478bd9Sstevel@tonic-gate pushl %esi / yt 7727c478bd9Sstevel@tonic-gate movl 12(%esp), %eax / xt, xt 7737c478bd9Sstevel@tonic-gate movl 16(%esp), %edx / xt, xt 7747c478bd9Sstevel@tonic-gate call UDivRem 7757c478bd9Sstevel@tonic-gate addl $12, %esp 7767c478bd9Sstevel@tonic-gate movl 36(%esp), %edi / x, 7777c478bd9Sstevel@tonic-gate testl %edi, %edi 7787c478bd9Sstevel@tonic-gate movl 8(%esp), %eax / rem, rem 7797c478bd9Sstevel@tonic-gate movl 12(%esp), %edx / rem, rem 7807c478bd9Sstevel@tonic-gate js .LL94 7817c478bd9Sstevel@tonic-gate addl $20, %esp 7827c478bd9Sstevel@tonic-gate popl %esi 7837c478bd9Sstevel@tonic-gate popl %edi 7847c478bd9Sstevel@tonic-gate ret $16 7857c478bd9Sstevel@tonic-gate .align 16 7867c478bd9Sstevel@tonic-gate.LL92: 7877c478bd9Sstevel@tonic-gate negl %esi 7887c478bd9Sstevel@tonic-gate adcl $0, %edi 7897c478bd9Sstevel@tonic-gate negl %edi 7907c478bd9Sstevel@tonic-gate testl %edx, %edx / y 7917c478bd9Sstevel@tonic-gate movl %esi, (%esp) /, xt 7927c478bd9Sstevel@tonic-gate movl %edi, 4(%esp) /, xt 7937c478bd9Sstevel@tonic-gate movl %eax, %esi / y, yt 7947c478bd9Sstevel@tonic-gate movl %edx, %edi / y, yt 7957c478bd9Sstevel@tonic-gate jns .LL90 7967c478bd9Sstevel@tonic-gate .align 16 7977c478bd9Sstevel@tonic-gate.LL93: 7987c478bd9Sstevel@tonic-gate negl %esi / yt 7997c478bd9Sstevel@tonic-gate adcl $0, %edi /, yt 8007c478bd9Sstevel@tonic-gate negl %edi / yt 8017c478bd9Sstevel@tonic-gate jmp .LL90 8027c478bd9Sstevel@tonic-gate .align 16 8037c478bd9Sstevel@tonic-gate.LL94: 8047c478bd9Sstevel@tonic-gate negl %eax / rem 8057c478bd9Sstevel@tonic-gate adcl $0, %edx /, rem 8067c478bd9Sstevel@tonic-gate addl $20, %esp 8077c478bd9Sstevel@tonic-gate popl %esi 8087c478bd9Sstevel@tonic-gate negl %edx / rem 8097c478bd9Sstevel@tonic-gate popl %edi 8107c478bd9Sstevel@tonic-gate ret $16 8117c478bd9Sstevel@tonic-gate SET_SIZE(__rem64) 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate/* 8147c478bd9Sstevel@tonic-gate * __udivrem64 8157c478bd9Sstevel@tonic-gate * 8167c478bd9Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the 8177c478bd9Sstevel@tonic-gate * quotient in %edx:%eax, and the remainder in %ecx:%esi. __udivrem64 8187c478bd9Sstevel@tonic-gate * pops the arguments on return. 8197c478bd9Sstevel@tonic-gate */ 8207c478bd9Sstevel@tonic-gate ENTRY(__udivrem64) 8217c478bd9Sstevel@tonic-gate subl $12, %esp 8227c478bd9Sstevel@tonic-gate movl %esp, %ecx /, tmp64 8237c478bd9Sstevel@tonic-gate movl 16(%esp), %eax / x, x 8247c478bd9Sstevel@tonic-gate movl 20(%esp), %edx / x, x 8257c478bd9Sstevel@tonic-gate pushl %ecx / tmp64 8267c478bd9Sstevel@tonic-gate pushl 32(%esp) / y 8277c478bd9Sstevel@tonic-gate pushl 32(%esp) 8287c478bd9Sstevel@tonic-gate call UDivRem 8297c478bd9Sstevel@tonic-gate movl 16(%esp), %ecx / rem, tmp63 8307c478bd9Sstevel@tonic-gate movl 12(%esp), %esi / rem 8317c478bd9Sstevel@tonic-gate addl $24, %esp 8327c478bd9Sstevel@tonic-gate ret $16 8337c478bd9Sstevel@tonic-gate SET_SIZE(__udivrem64) 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate/* 8367c478bd9Sstevel@tonic-gate * Signed division with remainder. 8377c478bd9Sstevel@tonic-gate */ 8387c478bd9Sstevel@tonic-gate/ int64_t 8397c478bd9Sstevel@tonic-gate/ SDivRem(int64_t x, int64_t y, int64_t * pmod) 8407c478bd9Sstevel@tonic-gate/ { 8417c478bd9Sstevel@tonic-gate/ int negative; 8427c478bd9Sstevel@tonic-gate/ uint64_t xt, yt, r, rem; 8437c478bd9Sstevel@tonic-gate/ 8447c478bd9Sstevel@tonic-gate/ if (x < 0) { 8457c478bd9Sstevel@tonic-gate/ xt = -(uint64_t) x; 8467c478bd9Sstevel@tonic-gate/ negative = 1; 8477c478bd9Sstevel@tonic-gate/ } else { 8487c478bd9Sstevel@tonic-gate/ xt = x; 8497c478bd9Sstevel@tonic-gate/ negative = 0; 8507c478bd9Sstevel@tonic-gate/ } 8517c478bd9Sstevel@tonic-gate/ if (y < 0) { 8527c478bd9Sstevel@tonic-gate/ yt = -(uint64_t) y; 8537c478bd9Sstevel@tonic-gate/ negative ^= 1; 8547c478bd9Sstevel@tonic-gate/ } else { 8557c478bd9Sstevel@tonic-gate/ yt = y; 8567c478bd9Sstevel@tonic-gate/ } 8577c478bd9Sstevel@tonic-gate/ r = UDivRem(xt, yt, &rem); 8587c478bd9Sstevel@tonic-gate/ *pmod = (x < 0 ? (int64_t) - rem : rem); 8597c478bd9Sstevel@tonic-gate/ return (negative ? (int64_t) - r : r); 8607c478bd9Sstevel@tonic-gate/ } 8617c478bd9Sstevel@tonic-gate ENTRY(SDivRem) 8627c478bd9Sstevel@tonic-gate pushl %ebp 8637c478bd9Sstevel@tonic-gate pushl %edi 8647c478bd9Sstevel@tonic-gate pushl %esi 8657c478bd9Sstevel@tonic-gate subl $24, %esp 8667c478bd9Sstevel@tonic-gate testl %edx, %edx / x 8677c478bd9Sstevel@tonic-gate movl %edx, %edi / x, x 8687c478bd9Sstevel@tonic-gate js .LL73 8697c478bd9Sstevel@tonic-gate movl 44(%esp), %esi / y, 8707c478bd9Sstevel@tonic-gate xorl %ebp, %ebp / negative 8717c478bd9Sstevel@tonic-gate testl %esi, %esi 8727c478bd9Sstevel@tonic-gate movl %edx, 12(%esp) / x, xt 8737c478bd9Sstevel@tonic-gate movl %eax, 8(%esp) / x, xt 8747c478bd9Sstevel@tonic-gate movl 40(%esp), %edx / y, yt 8757c478bd9Sstevel@tonic-gate movl 44(%esp), %ecx / y, yt 8767c478bd9Sstevel@tonic-gate js .LL74 8777c478bd9Sstevel@tonic-gate.LL70: 8787c478bd9Sstevel@tonic-gate leal 16(%esp), %eax /, tmp70 8797c478bd9Sstevel@tonic-gate pushl %eax / tmp70 8807c478bd9Sstevel@tonic-gate pushl %ecx / yt 8817c478bd9Sstevel@tonic-gate pushl %edx / yt 8827c478bd9Sstevel@tonic-gate movl 20(%esp), %eax / xt, xt 8837c478bd9Sstevel@tonic-gate movl 24(%esp), %edx / xt, xt 8847c478bd9Sstevel@tonic-gate call UDivRem 8857c478bd9Sstevel@tonic-gate movl %edx, 16(%esp) /, r 8867c478bd9Sstevel@tonic-gate movl %eax, 12(%esp) /, r 8877c478bd9Sstevel@tonic-gate addl $12, %esp 8887c478bd9Sstevel@tonic-gate testl %edi, %edi / x 8897c478bd9Sstevel@tonic-gate movl 16(%esp), %edx / rem, rem 8907c478bd9Sstevel@tonic-gate movl 20(%esp), %ecx / rem, rem 8917c478bd9Sstevel@tonic-gate js .LL75 8927c478bd9Sstevel@tonic-gate.LL71: 8937c478bd9Sstevel@tonic-gate movl 48(%esp), %edi / pmod, pmod 8947c478bd9Sstevel@tonic-gate testl %ebp, %ebp / negative 8957c478bd9Sstevel@tonic-gate movl %edx, (%edi) / rem,* pmod 8967c478bd9Sstevel@tonic-gate movl %ecx, 4(%edi) / rem, 8977c478bd9Sstevel@tonic-gate movl (%esp), %eax / r, r 8987c478bd9Sstevel@tonic-gate movl 4(%esp), %edx / r, r 8997c478bd9Sstevel@tonic-gate je .LL72 9007c478bd9Sstevel@tonic-gate negl %eax / r 9017c478bd9Sstevel@tonic-gate adcl $0, %edx /, r 9027c478bd9Sstevel@tonic-gate negl %edx / r 9037c478bd9Sstevel@tonic-gate.LL72: 9047c478bd9Sstevel@tonic-gate addl $24, %esp 9057c478bd9Sstevel@tonic-gate popl %esi 9067c478bd9Sstevel@tonic-gate popl %edi 9077c478bd9Sstevel@tonic-gate popl %ebp 9087c478bd9Sstevel@tonic-gate ret 9097c478bd9Sstevel@tonic-gate .align 16 9107c478bd9Sstevel@tonic-gate.LL73: 9117c478bd9Sstevel@tonic-gate negl %eax 9127c478bd9Sstevel@tonic-gate adcl $0, %edx 9137c478bd9Sstevel@tonic-gate movl 44(%esp), %esi / y, 9147c478bd9Sstevel@tonic-gate negl %edx 9157c478bd9Sstevel@tonic-gate testl %esi, %esi 9167c478bd9Sstevel@tonic-gate movl %edx, 12(%esp) /, xt 9177c478bd9Sstevel@tonic-gate movl %eax, 8(%esp) /, xt 9187c478bd9Sstevel@tonic-gate movl $1, %ebp /, negative 9197c478bd9Sstevel@tonic-gate movl 40(%esp), %edx / y, yt 9207c478bd9Sstevel@tonic-gate movl 44(%esp), %ecx / y, yt 9217c478bd9Sstevel@tonic-gate jns .LL70 9227c478bd9Sstevel@tonic-gate .align 16 9237c478bd9Sstevel@tonic-gate.LL74: 9247c478bd9Sstevel@tonic-gate negl %edx / yt 9257c478bd9Sstevel@tonic-gate adcl $0, %ecx /, yt 9267c478bd9Sstevel@tonic-gate negl %ecx / yt 9277c478bd9Sstevel@tonic-gate xorl $1, %ebp /, negative 9287c478bd9Sstevel@tonic-gate jmp .LL70 9297c478bd9Sstevel@tonic-gate .align 16 9307c478bd9Sstevel@tonic-gate.LL75: 9317c478bd9Sstevel@tonic-gate negl %edx / rem 9327c478bd9Sstevel@tonic-gate adcl $0, %ecx /, rem 9337c478bd9Sstevel@tonic-gate negl %ecx / rem 9347c478bd9Sstevel@tonic-gate jmp .LL71 9357c478bd9Sstevel@tonic-gate SET_SIZE(SDivRem) 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate/* 9387c478bd9Sstevel@tonic-gate * __divrem64 9397c478bd9Sstevel@tonic-gate * 9407c478bd9Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the 9417c478bd9Sstevel@tonic-gate * quotient in %edx:%eax, and the remainder in %ecx:%esi. __divrem64 9427c478bd9Sstevel@tonic-gate * pops the arguments on return. 9437c478bd9Sstevel@tonic-gate */ 9447c478bd9Sstevel@tonic-gate ENTRY(__divrem64) 9457c478bd9Sstevel@tonic-gate subl $20, %esp 9467c478bd9Sstevel@tonic-gate movl %esp, %ecx /, tmp64 9477c478bd9Sstevel@tonic-gate movl 24(%esp), %eax / x, x 9487c478bd9Sstevel@tonic-gate movl 28(%esp), %edx / x, x 9497c478bd9Sstevel@tonic-gate pushl %ecx / tmp64 9507c478bd9Sstevel@tonic-gate pushl 40(%esp) / y 9517c478bd9Sstevel@tonic-gate pushl 40(%esp) 9527c478bd9Sstevel@tonic-gate call SDivRem 9537c478bd9Sstevel@tonic-gate movl 16(%esp), %ecx 9547c478bd9Sstevel@tonic-gate movl 12(%esp),%esi / rem 9557c478bd9Sstevel@tonic-gate addl $32, %esp 9567c478bd9Sstevel@tonic-gate ret $16 9577c478bd9Sstevel@tonic-gate SET_SIZE(__divrem64) 958