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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate/* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 2789518a1cSdmick#if !defined(lint) 2889518a1cSdmick .ident "%Z%%M% %I% %E% SMI" 2989518a1cSdmick 3089518a1cSdmick .file "muldiv.s" 317c478bd9Sstevel@tonic-gate#endif 327c478bd9Sstevel@tonic-gate 3389518a1cSdmick#if defined(__i386) && !defined(__amd64) 3489518a1cSdmick 3589518a1cSdmick/* 3689518a1cSdmick * Helper routines for 32-bit compilers to perform 64-bit math. 3789518a1cSdmick * These are used both by the Sun and GCC compilers. 3889518a1cSdmick */ 3989518a1cSdmick 407c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h> 4189518a1cSdmick#include <sys/asm_misc.h> 4289518a1cSdmick 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate#if defined(__lint) 4589518a1cSdmick#include <sys/types.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate/* ARGSUSED */ 487c478bd9Sstevel@tonic-gateint64_t 497c478bd9Sstevel@tonic-gate__mul64(int64_t a, int64_t b) 50*55fea89dSDan Cross{ 51*55fea89dSDan Cross return (0); 527c478bd9Sstevel@tonic-gate} 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate#else /* __lint */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate/ 577c478bd9Sstevel@tonic-gate/ function __mul64(A,B:Longint):Longint; 587c478bd9Sstevel@tonic-gate/ {Overflow is not checked} 597c478bd9Sstevel@tonic-gate/ 607c478bd9Sstevel@tonic-gate/ We essentially do multiply by longhand, using base 2**32 digits. 617c478bd9Sstevel@tonic-gate/ a b parameter A 627c478bd9Sstevel@tonic-gate/ x c d parameter B 637c478bd9Sstevel@tonic-gate/ --------- 647c478bd9Sstevel@tonic-gate/ ad bd 657c478bd9Sstevel@tonic-gate/ ac bc 667c478bd9Sstevel@tonic-gate/ ----------------- 677c478bd9Sstevel@tonic-gate/ ac ad+bc bd 687c478bd9Sstevel@tonic-gate/ 697c478bd9Sstevel@tonic-gate/ We can ignore ac and top 32 bits of ad+bc: if <> 0, overflow happened. 707c478bd9Sstevel@tonic-gate/ 717c478bd9Sstevel@tonic-gate ENTRY(__mul64) 727c478bd9Sstevel@tonic-gate push %ebp 737c478bd9Sstevel@tonic-gate mov %esp,%ebp 747c478bd9Sstevel@tonic-gate pushl %esi 757c478bd9Sstevel@tonic-gate mov 12(%ebp),%eax / A.hi (a) 767c478bd9Sstevel@tonic-gate mull 16(%ebp) / Multiply A.hi by B.lo (produces ad) 777c478bd9Sstevel@tonic-gate xchg %ecx,%eax / ecx = bottom half of ad. 787c478bd9Sstevel@tonic-gate movl 8(%ebp),%eax / A.Lo (b) 797c478bd9Sstevel@tonic-gate movl %eax,%esi / Save A.lo for later 807c478bd9Sstevel@tonic-gate mull 16(%ebp) / Multiply A.Lo by B.LO (dx:ax = bd.) 817c478bd9Sstevel@tonic-gate addl %edx,%ecx / cx is ad 827c478bd9Sstevel@tonic-gate xchg %eax,%esi / esi is bd, eax = A.lo (d) 837c478bd9Sstevel@tonic-gate mull 20(%ebp) / Multiply A.lo * B.hi (producing bc) 847c478bd9Sstevel@tonic-gate addl %ecx,%eax / Produce ad+bc 857c478bd9Sstevel@tonic-gate movl %esi,%edx 867c478bd9Sstevel@tonic-gate xchg %eax,%edx 877c478bd9Sstevel@tonic-gate popl %esi 887c478bd9Sstevel@tonic-gate movl %ebp,%esp 897c478bd9Sstevel@tonic-gate popl %ebp 907c478bd9Sstevel@tonic-gate ret $16 917c478bd9Sstevel@tonic-gate SET_SIZE(__mul64) 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate#endif /* __lint */ 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate/* 967c478bd9Sstevel@tonic-gate * C support for 64-bit modulo and division. 977c478bd9Sstevel@tonic-gate * Hand-customized compiler output - see comments for details. 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate#if defined(__lint) 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate/* ARGSUSED */ 1027c478bd9Sstevel@tonic-gateuint64_t 1037c478bd9Sstevel@tonic-gate__udiv64(uint64_t a, uint64_t b) 1047c478bd9Sstevel@tonic-gate{ return (0); } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate/* ARGSUSED */ 1077c478bd9Sstevel@tonic-gateuint64_t 1087c478bd9Sstevel@tonic-gate__urem64(int64_t a, int64_t b) 1097c478bd9Sstevel@tonic-gate{ return (0); } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate/* ARGSUSED */ 1127c478bd9Sstevel@tonic-gateint64_t 1137c478bd9Sstevel@tonic-gate__div64(int64_t a, int64_t b) 1147c478bd9Sstevel@tonic-gate{ return (0); } 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate/* ARGSUSED */ 1177c478bd9Sstevel@tonic-gateint64_t 1187c478bd9Sstevel@tonic-gate__rem64(int64_t a, int64_t b) 1197c478bd9Sstevel@tonic-gate{ return (0); } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate#else /* __lint */ 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate/ /* 1247c478bd9Sstevel@tonic-gate/ * Unsigned division with remainder. 1257c478bd9Sstevel@tonic-gate/ * Divide two uint64_ts, and calculate remainder. 1267c478bd9Sstevel@tonic-gate/ */ 1277c478bd9Sstevel@tonic-gate/ uint64_t 1287c478bd9Sstevel@tonic-gate/ UDivRem(uint64_t x, uint64_t y, uint64_t * pmod) 1297c478bd9Sstevel@tonic-gate/ { 1307c478bd9Sstevel@tonic-gate/ /* simple cases: y is a single uint32_t */ 1317c478bd9Sstevel@tonic-gate/ if (HI(y) == 0) { 1327c478bd9Sstevel@tonic-gate/ uint32_t div_hi, div_rem; 1337c478bd9Sstevel@tonic-gate/ uint32_t q0, q1; 134*55fea89dSDan Cross/ 1357c478bd9Sstevel@tonic-gate/ /* calculate q1 */ 1367c478bd9Sstevel@tonic-gate/ if (HI(x) < LO(y)) { 1377c478bd9Sstevel@tonic-gate/ /* result is a single uint32_t, use one division */ 1387c478bd9Sstevel@tonic-gate/ q1 = 0; 1397c478bd9Sstevel@tonic-gate/ div_hi = HI(x); 1407c478bd9Sstevel@tonic-gate/ } else { 1417c478bd9Sstevel@tonic-gate/ /* result is a double uint32_t, use two divisions */ 1427c478bd9Sstevel@tonic-gate/ A_DIV32(HI(x), 0, LO(y), q1, div_hi); 1437c478bd9Sstevel@tonic-gate/ } 144*55fea89dSDan Cross/ 1457c478bd9Sstevel@tonic-gate/ /* calculate q0 and remainder */ 1467c478bd9Sstevel@tonic-gate/ A_DIV32(LO(x), div_hi, LO(y), q0, div_rem); 147*55fea89dSDan Cross/ 1487c478bd9Sstevel@tonic-gate/ /* return remainder */ 1497c478bd9Sstevel@tonic-gate/ *pmod = div_rem; 150*55fea89dSDan Cross/ 1517c478bd9Sstevel@tonic-gate/ /* return result */ 1527c478bd9Sstevel@tonic-gate/ return (HILO(q1, q0)); 153*55fea89dSDan Cross/ 1547c478bd9Sstevel@tonic-gate/ } else if (HI(x) < HI(y)) { 1557c478bd9Sstevel@tonic-gate/ /* HI(x) < HI(y) => x < y => result is 0 */ 156*55fea89dSDan Cross/ 1577c478bd9Sstevel@tonic-gate/ /* return remainder */ 1587c478bd9Sstevel@tonic-gate/ *pmod = x; 159*55fea89dSDan Cross/ 1607c478bd9Sstevel@tonic-gate/ /* return result */ 1617c478bd9Sstevel@tonic-gate/ return (0); 162*55fea89dSDan Cross/ 1637c478bd9Sstevel@tonic-gate/ } else { 1647c478bd9Sstevel@tonic-gate/ /* 1657c478bd9Sstevel@tonic-gate/ * uint64_t by uint64_t division, resulting in a one-uint32_t 1667c478bd9Sstevel@tonic-gate/ * result 1677c478bd9Sstevel@tonic-gate/ */ 1687c478bd9Sstevel@tonic-gate/ uint32_t y0, y1; 1697c478bd9Sstevel@tonic-gate/ uint32_t x1, x0; 1707c478bd9Sstevel@tonic-gate/ uint32_t q0; 1717c478bd9Sstevel@tonic-gate/ uint32_t normshift; 172*55fea89dSDan Cross/ 1737c478bd9Sstevel@tonic-gate/ /* normalize by shifting x and y so MSB(y) == 1 */ 1747c478bd9Sstevel@tonic-gate/ HIBIT(HI(y), normshift); /* index of highest 1 bit */ 1757c478bd9Sstevel@tonic-gate/ normshift = 31 - normshift; 176*55fea89dSDan Cross/ 1777c478bd9Sstevel@tonic-gate/ if (normshift == 0) { 1787c478bd9Sstevel@tonic-gate/ /* no shifting needed, and x < 2*y so q <= 1 */ 1797c478bd9Sstevel@tonic-gate/ y1 = HI(y); 1807c478bd9Sstevel@tonic-gate/ y0 = LO(y); 1817c478bd9Sstevel@tonic-gate/ x1 = HI(x); 1827c478bd9Sstevel@tonic-gate/ x0 = LO(x); 183*55fea89dSDan Cross/ 1847c478bd9Sstevel@tonic-gate/ /* if x >= y then q = 1 (note x1 >= y1) */ 1857c478bd9Sstevel@tonic-gate/ if (x1 > y1 || x0 >= y0) { 1867c478bd9Sstevel@tonic-gate/ q0 = 1; 1877c478bd9Sstevel@tonic-gate/ /* subtract y from x to get remainder */ 1887c478bd9Sstevel@tonic-gate/ A_SUB2(y0, y1, x0, x1); 1897c478bd9Sstevel@tonic-gate/ } else { 1907c478bd9Sstevel@tonic-gate/ q0 = 0; 1917c478bd9Sstevel@tonic-gate/ } 192*55fea89dSDan Cross/ 1937c478bd9Sstevel@tonic-gate/ /* return remainder */ 1947c478bd9Sstevel@tonic-gate/ *pmod = HILO(x1, x0); 195*55fea89dSDan Cross/ 1967c478bd9Sstevel@tonic-gate/ /* return result */ 1977c478bd9Sstevel@tonic-gate/ return (q0); 198*55fea89dSDan Cross/ 1997c478bd9Sstevel@tonic-gate/ } else { 2007c478bd9Sstevel@tonic-gate/ /* 2017c478bd9Sstevel@tonic-gate/ * the last case: result is one uint32_t, but we need to 2027c478bd9Sstevel@tonic-gate/ * normalize 2037c478bd9Sstevel@tonic-gate/ */ 2047c478bd9Sstevel@tonic-gate/ uint64_t dt; 2057c478bd9Sstevel@tonic-gate/ uint32_t t0, t1, x2; 206*55fea89dSDan Cross/ 2077c478bd9Sstevel@tonic-gate/ /* normalize y */ 2087c478bd9Sstevel@tonic-gate/ dt = (y << normshift); 2097c478bd9Sstevel@tonic-gate/ y1 = HI(dt); 2107c478bd9Sstevel@tonic-gate/ y0 = LO(dt); 211*55fea89dSDan Cross/ 2127c478bd9Sstevel@tonic-gate/ /* normalize x (we need 3 uint32_ts!!!) */ 2137c478bd9Sstevel@tonic-gate/ x2 = (HI(x) >> (32 - normshift)); 2147c478bd9Sstevel@tonic-gate/ dt = (x << normshift); 2157c478bd9Sstevel@tonic-gate/ x1 = HI(dt); 2167c478bd9Sstevel@tonic-gate/ x0 = LO(dt); 217*55fea89dSDan Cross/ 2187c478bd9Sstevel@tonic-gate/ /* estimate q0, and reduce x to a two uint32_t value */ 2197c478bd9Sstevel@tonic-gate/ A_DIV32(x1, x2, y1, q0, x1); 220*55fea89dSDan Cross/ 2217c478bd9Sstevel@tonic-gate/ /* adjust q0 down if too high */ 2227c478bd9Sstevel@tonic-gate/ /* 2237c478bd9Sstevel@tonic-gate/ * because of the limited range of x2 we can only be 2247c478bd9Sstevel@tonic-gate/ * one off 2257c478bd9Sstevel@tonic-gate/ */ 2267c478bd9Sstevel@tonic-gate/ A_MUL32(y0, q0, t0, t1); 2277c478bd9Sstevel@tonic-gate/ if (t1 > x1 || (t1 == x1 && t0 > x0)) { 2287c478bd9Sstevel@tonic-gate/ q0--; 2297c478bd9Sstevel@tonic-gate/ A_SUB2(y0, y1, t0, t1); 2307c478bd9Sstevel@tonic-gate/ } 2317c478bd9Sstevel@tonic-gate/ /* return remainder */ 2327c478bd9Sstevel@tonic-gate/ /* subtract product from x to get remainder */ 2337c478bd9Sstevel@tonic-gate/ A_SUB2(t0, t1, x0, x1); 2347c478bd9Sstevel@tonic-gate/ *pmod = (HILO(x1, x0) >> normshift); 235*55fea89dSDan Cross/ 2367c478bd9Sstevel@tonic-gate/ /* return result */ 2377c478bd9Sstevel@tonic-gate/ return (q0); 2387c478bd9Sstevel@tonic-gate/ } 2397c478bd9Sstevel@tonic-gate/ } 2407c478bd9Sstevel@tonic-gate/ } 2417c478bd9Sstevel@tonic-gate ENTRY(UDivRem) 2427c478bd9Sstevel@tonic-gate pushl %ebp 2437c478bd9Sstevel@tonic-gate pushl %edi 2447c478bd9Sstevel@tonic-gate pushl %esi 2457c478bd9Sstevel@tonic-gate subl $48, %esp 2467c478bd9Sstevel@tonic-gate movl 68(%esp), %edi / y, 2477c478bd9Sstevel@tonic-gate testl %edi, %edi / tmp63 2487c478bd9Sstevel@tonic-gate movl %eax, 40(%esp) / x, x 2497c478bd9Sstevel@tonic-gate movl %edx, 44(%esp) / x, x 2507c478bd9Sstevel@tonic-gate movl %edi, %esi /, tmp62 2517c478bd9Sstevel@tonic-gate movl %edi, %ecx / tmp62, tmp63 2527c478bd9Sstevel@tonic-gate jne .LL2 2537c478bd9Sstevel@tonic-gate movl %edx, %eax /, tmp68 2547c478bd9Sstevel@tonic-gate cmpl 64(%esp), %eax / y, tmp68 2557c478bd9Sstevel@tonic-gate jae .LL21 2567c478bd9Sstevel@tonic-gate.LL4: 2577c478bd9Sstevel@tonic-gate movl 72(%esp), %ebp / pmod, 2587c478bd9Sstevel@tonic-gate xorl %esi, %esi / <result> 2597c478bd9Sstevel@tonic-gate movl 40(%esp), %eax / x, q0 2607c478bd9Sstevel@tonic-gate movl %ecx, %edi / <result>, <result> 2617c478bd9Sstevel@tonic-gate divl 64(%esp) / y 2627c478bd9Sstevel@tonic-gate movl %edx, (%ebp) / div_rem, 2637c478bd9Sstevel@tonic-gate xorl %edx, %edx / q0 2647c478bd9Sstevel@tonic-gate addl %eax, %esi / q0, <result> 2657c478bd9Sstevel@tonic-gate movl $0, 4(%ebp) 2667c478bd9Sstevel@tonic-gate adcl %edx, %edi / q0, <result> 2677c478bd9Sstevel@tonic-gate addl $48, %esp 2687c478bd9Sstevel@tonic-gate movl %esi, %eax / <result>, <result> 2697c478bd9Sstevel@tonic-gate popl %esi 2707c478bd9Sstevel@tonic-gate movl %edi, %edx / <result>, <result> 2717c478bd9Sstevel@tonic-gate popl %edi 2727c478bd9Sstevel@tonic-gate popl %ebp 2737c478bd9Sstevel@tonic-gate ret 2747c478bd9Sstevel@tonic-gate .align 16 2757c478bd9Sstevel@tonic-gate.LL2: 2767c478bd9Sstevel@tonic-gate movl 44(%esp), %eax / x, 2777c478bd9Sstevel@tonic-gate xorl %edx, %edx 2787c478bd9Sstevel@tonic-gate cmpl %esi, %eax / tmp62, tmp5 2797c478bd9Sstevel@tonic-gate movl %eax, 32(%esp) / tmp5, 2807c478bd9Sstevel@tonic-gate movl %edx, 36(%esp) 2817c478bd9Sstevel@tonic-gate jae .LL6 2827c478bd9Sstevel@tonic-gate movl 72(%esp), %esi / pmod, 2837c478bd9Sstevel@tonic-gate movl 40(%esp), %ebp / x, 2847c478bd9Sstevel@tonic-gate movl 44(%esp), %ecx / x, 2857c478bd9Sstevel@tonic-gate movl %ebp, (%esi) 2867c478bd9Sstevel@tonic-gate movl %ecx, 4(%esi) 2877c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 2887c478bd9Sstevel@tonic-gate xorl %esi, %esi / <result> 2897c478bd9Sstevel@tonic-gate.LL22: 2907c478bd9Sstevel@tonic-gate addl $48, %esp 2917c478bd9Sstevel@tonic-gate movl %esi, %eax / <result>, <result> 2927c478bd9Sstevel@tonic-gate popl %esi 2937c478bd9Sstevel@tonic-gate movl %edi, %edx / <result>, <result> 2947c478bd9Sstevel@tonic-gate popl %edi 2957c478bd9Sstevel@tonic-gate popl %ebp 2967c478bd9Sstevel@tonic-gate ret 2977c478bd9Sstevel@tonic-gate .align 16 2987c478bd9Sstevel@tonic-gate.LL21: 2997c478bd9Sstevel@tonic-gate movl %edi, %edx / tmp63, div_hi 3007c478bd9Sstevel@tonic-gate divl 64(%esp) / y 3017c478bd9Sstevel@tonic-gate movl %eax, %ecx /, q1 3027c478bd9Sstevel@tonic-gate jmp .LL4 3037c478bd9Sstevel@tonic-gate .align 16 3047c478bd9Sstevel@tonic-gate.LL6: 3057c478bd9Sstevel@tonic-gate movl $31, %edi /, tmp87 3067c478bd9Sstevel@tonic-gate bsrl %esi,%edx / tmp62, normshift 3077c478bd9Sstevel@tonic-gate subl %edx, %edi / normshift, tmp87 3087c478bd9Sstevel@tonic-gate movl %edi, 28(%esp) / tmp87, 3097c478bd9Sstevel@tonic-gate jne .LL8 3107c478bd9Sstevel@tonic-gate movl 32(%esp), %edx /, x1 3117c478bd9Sstevel@tonic-gate cmpl %ecx, %edx / y1, x1 3127c478bd9Sstevel@tonic-gate movl 64(%esp), %edi / y, y0 3137c478bd9Sstevel@tonic-gate movl 40(%esp), %esi / x, x0 3147c478bd9Sstevel@tonic-gate ja .LL10 3157c478bd9Sstevel@tonic-gate xorl %ebp, %ebp / q0 3167c478bd9Sstevel@tonic-gate cmpl %edi, %esi / y0, x0 3177c478bd9Sstevel@tonic-gate jb .LL11 3187c478bd9Sstevel@tonic-gate.LL10: 3197c478bd9Sstevel@tonic-gate movl $1, %ebp /, q0 3207c478bd9Sstevel@tonic-gate subl %edi,%esi / y0, x0 3217c478bd9Sstevel@tonic-gate sbbl %ecx,%edx / tmp63, x1 3227c478bd9Sstevel@tonic-gate.LL11: 3237c478bd9Sstevel@tonic-gate movl %edx, %ecx / x1, x1 3247c478bd9Sstevel@tonic-gate xorl %edx, %edx / x1 3257c478bd9Sstevel@tonic-gate xorl %edi, %edi / x0 3267c478bd9Sstevel@tonic-gate addl %esi, %edx / x0, x1 3277c478bd9Sstevel@tonic-gate adcl %edi, %ecx / x0, x1 3287c478bd9Sstevel@tonic-gate movl 72(%esp), %esi / pmod, 3297c478bd9Sstevel@tonic-gate movl %edx, (%esi) / x1, 3307c478bd9Sstevel@tonic-gate movl %ecx, 4(%esi) / x1, 3317c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 3327c478bd9Sstevel@tonic-gate movl %ebp, %esi / q0, <result> 3337c478bd9Sstevel@tonic-gate jmp .LL22 3347c478bd9Sstevel@tonic-gate .align 16 3357c478bd9Sstevel@tonic-gate.LL8: 3367c478bd9Sstevel@tonic-gate movb 28(%esp), %cl 3377c478bd9Sstevel@tonic-gate movl 64(%esp), %esi / y, dt 3387c478bd9Sstevel@tonic-gate movl 68(%esp), %edi / y, dt 3397c478bd9Sstevel@tonic-gate shldl %esi, %edi /, dt, dt 3407c478bd9Sstevel@tonic-gate sall %cl, %esi /, dt 3417c478bd9Sstevel@tonic-gate andl $32, %ecx 3427c478bd9Sstevel@tonic-gate jne .LL23 3437c478bd9Sstevel@tonic-gate.LL17: 3447c478bd9Sstevel@tonic-gate movl $32, %ecx /, tmp102 3457c478bd9Sstevel@tonic-gate subl 28(%esp), %ecx /, tmp102 3467c478bd9Sstevel@tonic-gate movl %esi, %ebp / dt, y0 3477c478bd9Sstevel@tonic-gate movl 32(%esp), %esi 3487c478bd9Sstevel@tonic-gate shrl %cl, %esi / tmp102, 3497c478bd9Sstevel@tonic-gate movl %edi, 24(%esp) / tmp99, 3507c478bd9Sstevel@tonic-gate movb 28(%esp), %cl 3517c478bd9Sstevel@tonic-gate movl %esi, 12(%esp) /, x2 3527c478bd9Sstevel@tonic-gate movl 44(%esp), %edi / x, dt 3537c478bd9Sstevel@tonic-gate movl 40(%esp), %esi / x, dt 3547c478bd9Sstevel@tonic-gate shldl %esi, %edi /, dt, dt 3557c478bd9Sstevel@tonic-gate sall %cl, %esi /, dt 3567c478bd9Sstevel@tonic-gate andl $32, %ecx 3577c478bd9Sstevel@tonic-gate je .LL18 3587c478bd9Sstevel@tonic-gate movl %esi, %edi / dt, dt 3597c478bd9Sstevel@tonic-gate xorl %esi, %esi / dt 3607c478bd9Sstevel@tonic-gate.LL18: 3617c478bd9Sstevel@tonic-gate movl %edi, %ecx / dt, 3627c478bd9Sstevel@tonic-gate movl %edi, %eax / tmp2, 3637c478bd9Sstevel@tonic-gate movl %ecx, (%esp) 3647c478bd9Sstevel@tonic-gate movl 12(%esp), %edx / x2, 3657c478bd9Sstevel@tonic-gate divl 24(%esp) 3667c478bd9Sstevel@tonic-gate movl %edx, %ecx /, x1 3677c478bd9Sstevel@tonic-gate xorl %edi, %edi 3687c478bd9Sstevel@tonic-gate movl %eax, 20(%esp) 3697c478bd9Sstevel@tonic-gate movl %ebp, %eax / y0, t0 3707c478bd9Sstevel@tonic-gate mull 20(%esp) 3717c478bd9Sstevel@tonic-gate cmpl %ecx, %edx / x1, t1 3727c478bd9Sstevel@tonic-gate movl %edi, 4(%esp) 3737c478bd9Sstevel@tonic-gate ja .LL14 3747c478bd9Sstevel@tonic-gate je .LL24 3757c478bd9Sstevel@tonic-gate.LL15: 3767c478bd9Sstevel@tonic-gate movl %ecx, %edi / x1, 3777c478bd9Sstevel@tonic-gate subl %eax,%esi / t0, x0 3787c478bd9Sstevel@tonic-gate sbbl %edx,%edi / t1, 3797c478bd9Sstevel@tonic-gate movl %edi, %eax /, x1 3807c478bd9Sstevel@tonic-gate movl %eax, %edx / x1, x1 3817c478bd9Sstevel@tonic-gate xorl %eax, %eax / x1 3827c478bd9Sstevel@tonic-gate xorl %ebp, %ebp / x0 3837c478bd9Sstevel@tonic-gate addl %esi, %eax / x0, x1 3847c478bd9Sstevel@tonic-gate adcl %ebp, %edx / x0, x1 3857c478bd9Sstevel@tonic-gate movb 28(%esp), %cl 3867c478bd9Sstevel@tonic-gate shrdl %edx, %eax /, x1, x1 3877c478bd9Sstevel@tonic-gate shrl %cl, %edx /, x1 3887c478bd9Sstevel@tonic-gate andl $32, %ecx 3897c478bd9Sstevel@tonic-gate je .LL16 3907c478bd9Sstevel@tonic-gate movl %edx, %eax / x1, x1 3917c478bd9Sstevel@tonic-gate xorl %edx, %edx / x1 3927c478bd9Sstevel@tonic-gate.LL16: 3937c478bd9Sstevel@tonic-gate movl 72(%esp), %ecx / pmod, 3947c478bd9Sstevel@tonic-gate movl 20(%esp), %esi /, <result> 3957c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 3967c478bd9Sstevel@tonic-gate movl %eax, (%ecx) / x1, 3977c478bd9Sstevel@tonic-gate movl %edx, 4(%ecx) / x1, 3987c478bd9Sstevel@tonic-gate jmp .LL22 3997c478bd9Sstevel@tonic-gate .align 16 4007c478bd9Sstevel@tonic-gate.LL24: 4017c478bd9Sstevel@tonic-gate cmpl %esi, %eax / x0, t0 4027c478bd9Sstevel@tonic-gate jbe .LL15 4037c478bd9Sstevel@tonic-gate.LL14: 4047c478bd9Sstevel@tonic-gate decl 20(%esp) 4057c478bd9Sstevel@tonic-gate subl %ebp,%eax / y0, t0 4067c478bd9Sstevel@tonic-gate sbbl 24(%esp),%edx /, t1 4077c478bd9Sstevel@tonic-gate jmp .LL15 4087c478bd9Sstevel@tonic-gate.LL23: 4097c478bd9Sstevel@tonic-gate movl %esi, %edi / dt, dt 4107c478bd9Sstevel@tonic-gate xorl %esi, %esi / dt 4117c478bd9Sstevel@tonic-gate jmp .LL17 4127c478bd9Sstevel@tonic-gate SET_SIZE(UDivRem) 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate/* 4157c478bd9Sstevel@tonic-gate * Unsigned division without remainder. 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate/ uint64_t 4187c478bd9Sstevel@tonic-gate/ UDiv(uint64_t x, uint64_t y) 4197c478bd9Sstevel@tonic-gate/ { 4207c478bd9Sstevel@tonic-gate/ if (HI(y) == 0) { 4217c478bd9Sstevel@tonic-gate/ /* simple cases: y is a single uint32_t */ 4227c478bd9Sstevel@tonic-gate/ uint32_t div_hi, div_rem; 4237c478bd9Sstevel@tonic-gate/ uint32_t q0, q1; 424*55fea89dSDan Cross/ 4257c478bd9Sstevel@tonic-gate/ /* calculate q1 */ 4267c478bd9Sstevel@tonic-gate/ if (HI(x) < LO(y)) { 4277c478bd9Sstevel@tonic-gate/ /* result is a single uint32_t, use one division */ 4287c478bd9Sstevel@tonic-gate/ q1 = 0; 4297c478bd9Sstevel@tonic-gate/ div_hi = HI(x); 4307c478bd9Sstevel@tonic-gate/ } else { 4317c478bd9Sstevel@tonic-gate/ /* result is a double uint32_t, use two divisions */ 4327c478bd9Sstevel@tonic-gate/ A_DIV32(HI(x), 0, LO(y), q1, div_hi); 4337c478bd9Sstevel@tonic-gate/ } 434*55fea89dSDan Cross/ 4357c478bd9Sstevel@tonic-gate/ /* calculate q0 and remainder */ 4367c478bd9Sstevel@tonic-gate/ A_DIV32(LO(x), div_hi, LO(y), q0, div_rem); 437*55fea89dSDan Cross/ 4387c478bd9Sstevel@tonic-gate/ /* return result */ 4397c478bd9Sstevel@tonic-gate/ return (HILO(q1, q0)); 440*55fea89dSDan Cross/ 4417c478bd9Sstevel@tonic-gate/ } else if (HI(x) < HI(y)) { 4427c478bd9Sstevel@tonic-gate/ /* HI(x) < HI(y) => x < y => result is 0 */ 443*55fea89dSDan Cross/ 4447c478bd9Sstevel@tonic-gate/ /* return result */ 4457c478bd9Sstevel@tonic-gate/ return (0); 446*55fea89dSDan Cross/ 4477c478bd9Sstevel@tonic-gate/ } else { 4487c478bd9Sstevel@tonic-gate/ /* 4497c478bd9Sstevel@tonic-gate/ * uint64_t by uint64_t division, resulting in a one-uint32_t 4507c478bd9Sstevel@tonic-gate/ * result 4517c478bd9Sstevel@tonic-gate/ */ 4527c478bd9Sstevel@tonic-gate/ uint32_t y0, y1; 4537c478bd9Sstevel@tonic-gate/ uint32_t x1, x0; 4547c478bd9Sstevel@tonic-gate/ uint32_t q0; 4557c478bd9Sstevel@tonic-gate/ unsigned normshift; 456*55fea89dSDan Cross/ 4577c478bd9Sstevel@tonic-gate/ /* normalize by shifting x and y so MSB(y) == 1 */ 4587c478bd9Sstevel@tonic-gate/ HIBIT(HI(y), normshift); /* index of highest 1 bit */ 4597c478bd9Sstevel@tonic-gate/ normshift = 31 - normshift; 460*55fea89dSDan Cross/ 4617c478bd9Sstevel@tonic-gate/ if (normshift == 0) { 4627c478bd9Sstevel@tonic-gate/ /* no shifting needed, and x < 2*y so q <= 1 */ 4637c478bd9Sstevel@tonic-gate/ y1 = HI(y); 4647c478bd9Sstevel@tonic-gate/ y0 = LO(y); 4657c478bd9Sstevel@tonic-gate/ x1 = HI(x); 4667c478bd9Sstevel@tonic-gate/ x0 = LO(x); 467*55fea89dSDan Cross/ 4687c478bd9Sstevel@tonic-gate/ /* if x >= y then q = 1 (note x1 >= y1) */ 4697c478bd9Sstevel@tonic-gate/ if (x1 > y1 || x0 >= y0) { 4707c478bd9Sstevel@tonic-gate/ q0 = 1; 4717c478bd9Sstevel@tonic-gate/ /* subtract y from x to get remainder */ 4727c478bd9Sstevel@tonic-gate/ /* A_SUB2(y0, y1, x0, x1); */ 4737c478bd9Sstevel@tonic-gate/ } else { 4747c478bd9Sstevel@tonic-gate/ q0 = 0; 4757c478bd9Sstevel@tonic-gate/ } 476*55fea89dSDan Cross/ 4777c478bd9Sstevel@tonic-gate/ /* return result */ 4787c478bd9Sstevel@tonic-gate/ return (q0); 479*55fea89dSDan Cross/ 4807c478bd9Sstevel@tonic-gate/ } else { 4817c478bd9Sstevel@tonic-gate/ /* 4827c478bd9Sstevel@tonic-gate/ * the last case: result is one uint32_t, but we need to 4837c478bd9Sstevel@tonic-gate/ * normalize 4847c478bd9Sstevel@tonic-gate/ */ 4857c478bd9Sstevel@tonic-gate/ uint64_t dt; 4867c478bd9Sstevel@tonic-gate/ uint32_t t0, t1, x2; 487*55fea89dSDan Cross/ 4887c478bd9Sstevel@tonic-gate/ /* normalize y */ 4897c478bd9Sstevel@tonic-gate/ dt = (y << normshift); 4907c478bd9Sstevel@tonic-gate/ y1 = HI(dt); 4917c478bd9Sstevel@tonic-gate/ y0 = LO(dt); 492*55fea89dSDan Cross/ 4937c478bd9Sstevel@tonic-gate/ /* normalize x (we need 3 uint32_ts!!!) */ 4947c478bd9Sstevel@tonic-gate/ x2 = (HI(x) >> (32 - normshift)); 4957c478bd9Sstevel@tonic-gate/ dt = (x << normshift); 4967c478bd9Sstevel@tonic-gate/ x1 = HI(dt); 4977c478bd9Sstevel@tonic-gate/ x0 = LO(dt); 498*55fea89dSDan Cross/ 4997c478bd9Sstevel@tonic-gate/ /* estimate q0, and reduce x to a two uint32_t value */ 5007c478bd9Sstevel@tonic-gate/ A_DIV32(x1, x2, y1, q0, x1); 501*55fea89dSDan Cross/ 5027c478bd9Sstevel@tonic-gate/ /* adjust q0 down if too high */ 5037c478bd9Sstevel@tonic-gate/ /* 5047c478bd9Sstevel@tonic-gate/ * because of the limited range of x2 we can only be 5057c478bd9Sstevel@tonic-gate/ * one off 5067c478bd9Sstevel@tonic-gate/ */ 5077c478bd9Sstevel@tonic-gate/ A_MUL32(y0, q0, t0, t1); 5087c478bd9Sstevel@tonic-gate/ if (t1 > x1 || (t1 == x1 && t0 > x0)) { 5097c478bd9Sstevel@tonic-gate/ q0--; 5107c478bd9Sstevel@tonic-gate/ } 5117c478bd9Sstevel@tonic-gate/ /* return result */ 5127c478bd9Sstevel@tonic-gate/ return (q0); 5137c478bd9Sstevel@tonic-gate/ } 5147c478bd9Sstevel@tonic-gate/ } 5157c478bd9Sstevel@tonic-gate/ } 5167c478bd9Sstevel@tonic-gate ENTRY(UDiv) 5177c478bd9Sstevel@tonic-gate pushl %ebp 5187c478bd9Sstevel@tonic-gate pushl %edi 5197c478bd9Sstevel@tonic-gate pushl %esi 5207c478bd9Sstevel@tonic-gate subl $40, %esp 5217c478bd9Sstevel@tonic-gate movl %edx, 36(%esp) / x, x 5227c478bd9Sstevel@tonic-gate movl 60(%esp), %edx / y, 5237c478bd9Sstevel@tonic-gate testl %edx, %edx / tmp62 5247c478bd9Sstevel@tonic-gate movl %eax, 32(%esp) / x, x 5257c478bd9Sstevel@tonic-gate movl %edx, %ecx / tmp61, tmp62 5267c478bd9Sstevel@tonic-gate movl %edx, %eax /, tmp61 5277c478bd9Sstevel@tonic-gate jne .LL26 5287c478bd9Sstevel@tonic-gate movl 36(%esp), %esi / x, 5297c478bd9Sstevel@tonic-gate cmpl 56(%esp), %esi / y, tmp67 5307c478bd9Sstevel@tonic-gate movl %esi, %eax /, tmp67 5317c478bd9Sstevel@tonic-gate movl %esi, %edx / tmp67, div_hi 5327c478bd9Sstevel@tonic-gate jb .LL28 5337c478bd9Sstevel@tonic-gate movl %ecx, %edx / tmp62, div_hi 5347c478bd9Sstevel@tonic-gate divl 56(%esp) / y 5357c478bd9Sstevel@tonic-gate movl %eax, %ecx /, q1 5367c478bd9Sstevel@tonic-gate.LL28: 5377c478bd9Sstevel@tonic-gate xorl %esi, %esi / <result> 5387c478bd9Sstevel@tonic-gate movl %ecx, %edi / <result>, <result> 5397c478bd9Sstevel@tonic-gate movl 32(%esp), %eax / x, q0 5407c478bd9Sstevel@tonic-gate xorl %ecx, %ecx / q0 5417c478bd9Sstevel@tonic-gate divl 56(%esp) / y 5427c478bd9Sstevel@tonic-gate addl %eax, %esi / q0, <result> 5437c478bd9Sstevel@tonic-gate adcl %ecx, %edi / q0, <result> 5447c478bd9Sstevel@tonic-gate.LL25: 5457c478bd9Sstevel@tonic-gate addl $40, %esp 5467c478bd9Sstevel@tonic-gate movl %esi, %eax / <result>, <result> 5477c478bd9Sstevel@tonic-gate popl %esi 5487c478bd9Sstevel@tonic-gate movl %edi, %edx / <result>, <result> 5497c478bd9Sstevel@tonic-gate popl %edi 5507c478bd9Sstevel@tonic-gate popl %ebp 5517c478bd9Sstevel@tonic-gate ret 5527c478bd9Sstevel@tonic-gate .align 16 5537c478bd9Sstevel@tonic-gate.LL26: 5547c478bd9Sstevel@tonic-gate movl 36(%esp), %esi / x, 5557c478bd9Sstevel@tonic-gate xorl %edi, %edi 5567c478bd9Sstevel@tonic-gate movl %esi, 24(%esp) / tmp1, 5577c478bd9Sstevel@tonic-gate movl %edi, 28(%esp) 5587c478bd9Sstevel@tonic-gate xorl %esi, %esi / <result> 5597c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 5607c478bd9Sstevel@tonic-gate cmpl %eax, 24(%esp) / tmp61, 5617c478bd9Sstevel@tonic-gate jb .LL25 5627c478bd9Sstevel@tonic-gate bsrl %eax,%ebp / tmp61, normshift 5637c478bd9Sstevel@tonic-gate movl $31, %eax /, tmp85 5647c478bd9Sstevel@tonic-gate subl %ebp, %eax / normshift, normshift 5657c478bd9Sstevel@tonic-gate jne .LL32 5667c478bd9Sstevel@tonic-gate movl 24(%esp), %eax /, x1 5677c478bd9Sstevel@tonic-gate cmpl %ecx, %eax / tmp62, x1 5687c478bd9Sstevel@tonic-gate movl 56(%esp), %esi / y, y0 5697c478bd9Sstevel@tonic-gate movl 32(%esp), %edx / x, x0 5707c478bd9Sstevel@tonic-gate ja .LL34 5717c478bd9Sstevel@tonic-gate xorl %eax, %eax / q0 5727c478bd9Sstevel@tonic-gate cmpl %esi, %edx / y0, x0 5737c478bd9Sstevel@tonic-gate jb .LL35 5747c478bd9Sstevel@tonic-gate.LL34: 5757c478bd9Sstevel@tonic-gate movl $1, %eax /, q0 5767c478bd9Sstevel@tonic-gate.LL35: 5777c478bd9Sstevel@tonic-gate movl %eax, %esi / q0, <result> 5787c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 5797c478bd9Sstevel@tonic-gate.LL45: 5807c478bd9Sstevel@tonic-gate addl $40, %esp 5817c478bd9Sstevel@tonic-gate movl %esi, %eax / <result>, <result> 5827c478bd9Sstevel@tonic-gate popl %esi 5837c478bd9Sstevel@tonic-gate movl %edi, %edx / <result>, <result> 5847c478bd9Sstevel@tonic-gate popl %edi 5857c478bd9Sstevel@tonic-gate popl %ebp 5867c478bd9Sstevel@tonic-gate ret 5877c478bd9Sstevel@tonic-gate .align 16 5887c478bd9Sstevel@tonic-gate.LL32: 5897c478bd9Sstevel@tonic-gate movb %al, %cl 5907c478bd9Sstevel@tonic-gate movl 56(%esp), %esi / y, 5917c478bd9Sstevel@tonic-gate movl 60(%esp), %edi / y, 5927c478bd9Sstevel@tonic-gate shldl %esi, %edi 5937c478bd9Sstevel@tonic-gate sall %cl, %esi 5947c478bd9Sstevel@tonic-gate andl $32, %ecx 5957c478bd9Sstevel@tonic-gate jne .LL43 5967c478bd9Sstevel@tonic-gate.LL40: 5977c478bd9Sstevel@tonic-gate movl $32, %ecx /, tmp96 5987c478bd9Sstevel@tonic-gate subl %eax, %ecx / normshift, tmp96 5997c478bd9Sstevel@tonic-gate movl %edi, %edx 6007c478bd9Sstevel@tonic-gate movl %edi, 20(%esp) /, dt 6017c478bd9Sstevel@tonic-gate movl 24(%esp), %ebp /, x2 6027c478bd9Sstevel@tonic-gate xorl %edi, %edi 6037c478bd9Sstevel@tonic-gate shrl %cl, %ebp / tmp96, x2 6047c478bd9Sstevel@tonic-gate movl %esi, 16(%esp) /, dt 6057c478bd9Sstevel@tonic-gate movb %al, %cl 6067c478bd9Sstevel@tonic-gate movl 32(%esp), %esi / x, dt 6077c478bd9Sstevel@tonic-gate movl %edi, 12(%esp) 6087c478bd9Sstevel@tonic-gate movl 36(%esp), %edi / x, dt 6097c478bd9Sstevel@tonic-gate shldl %esi, %edi /, dt, dt 6107c478bd9Sstevel@tonic-gate sall %cl, %esi /, dt 6117c478bd9Sstevel@tonic-gate andl $32, %ecx 6127c478bd9Sstevel@tonic-gate movl %edx, 8(%esp) 6137c478bd9Sstevel@tonic-gate je .LL41 6147c478bd9Sstevel@tonic-gate movl %esi, %edi / dt, dt 6157c478bd9Sstevel@tonic-gate xorl %esi, %esi / dt 6167c478bd9Sstevel@tonic-gate.LL41: 6177c478bd9Sstevel@tonic-gate xorl %ecx, %ecx 6187c478bd9Sstevel@tonic-gate movl %edi, %eax / tmp1, 6197c478bd9Sstevel@tonic-gate movl %ebp, %edx / x2, 6207c478bd9Sstevel@tonic-gate divl 8(%esp) 6217c478bd9Sstevel@tonic-gate movl %edx, %ebp /, x1 6227c478bd9Sstevel@tonic-gate movl %ecx, 4(%esp) 6237c478bd9Sstevel@tonic-gate movl %eax, %ecx /, q0 6247c478bd9Sstevel@tonic-gate movl 16(%esp), %eax / dt, 6257c478bd9Sstevel@tonic-gate mull %ecx / q0 6267c478bd9Sstevel@tonic-gate cmpl %ebp, %edx / x1, t1 6277c478bd9Sstevel@tonic-gate movl %edi, (%esp) 6287c478bd9Sstevel@tonic-gate movl %esi, %edi / dt, x0 6297c478bd9Sstevel@tonic-gate ja .LL38 6307c478bd9Sstevel@tonic-gate je .LL44 6317c478bd9Sstevel@tonic-gate.LL39: 6327c478bd9Sstevel@tonic-gate movl %ecx, %esi / q0, <result> 6337c478bd9Sstevel@tonic-gate.LL46: 6347c478bd9Sstevel@tonic-gate xorl %edi, %edi / <result> 6357c478bd9Sstevel@tonic-gate jmp .LL45 6367c478bd9Sstevel@tonic-gate.LL44: 6377c478bd9Sstevel@tonic-gate cmpl %edi, %eax / x0, t0 6387c478bd9Sstevel@tonic-gate jbe .LL39 6397c478bd9Sstevel@tonic-gate.LL38: 6407c478bd9Sstevel@tonic-gate decl %ecx / q0 6417c478bd9Sstevel@tonic-gate movl %ecx, %esi / q0, <result> 6427c478bd9Sstevel@tonic-gate jmp .LL46 6437c478bd9Sstevel@tonic-gate.LL43: 6447c478bd9Sstevel@tonic-gate movl %esi, %edi 6457c478bd9Sstevel@tonic-gate xorl %esi, %esi 6467c478bd9Sstevel@tonic-gate jmp .LL40 6477c478bd9Sstevel@tonic-gate SET_SIZE(UDiv) 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate/* 6507c478bd9Sstevel@tonic-gate * __udiv64 6517c478bd9Sstevel@tonic-gate * 6527c478bd9Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the 6537c478bd9Sstevel@tonic-gate * quotient in %edx:%eax. __udiv64 pops the arguments on return, 6547c478bd9Sstevel@tonic-gate */ 6557c478bd9Sstevel@tonic-gate ENTRY(__udiv64) 6567c478bd9Sstevel@tonic-gate movl 4(%esp), %eax / x, x 6577c478bd9Sstevel@tonic-gate movl 8(%esp), %edx / x, x 6587c478bd9Sstevel@tonic-gate pushl 16(%esp) / y 6597c478bd9Sstevel@tonic-gate pushl 16(%esp) 6607c478bd9Sstevel@tonic-gate call UDiv 6617c478bd9Sstevel@tonic-gate addl $8, %esp 6627c478bd9Sstevel@tonic-gate ret $16 6637c478bd9Sstevel@tonic-gate SET_SIZE(__udiv64) 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate/* 6667c478bd9Sstevel@tonic-gate * __urem64 6677c478bd9Sstevel@tonic-gate * 6687c478bd9Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the 6697c478bd9Sstevel@tonic-gate * remainder in %edx:%eax. __urem64 pops the arguments on return 6707c478bd9Sstevel@tonic-gate */ 6717c478bd9Sstevel@tonic-gate ENTRY(__urem64) 6727c478bd9Sstevel@tonic-gate subl $12, %esp 6737c478bd9Sstevel@tonic-gate movl %esp, %ecx /, tmp65 6747c478bd9Sstevel@tonic-gate movl 16(%esp), %eax / x, x 6757c478bd9Sstevel@tonic-gate movl 20(%esp), %edx / x, x 6767c478bd9Sstevel@tonic-gate pushl %ecx / tmp65 6777c478bd9Sstevel@tonic-gate pushl 32(%esp) / y 6787c478bd9Sstevel@tonic-gate pushl 32(%esp) 6797c478bd9Sstevel@tonic-gate call UDivRem 6807c478bd9Sstevel@tonic-gate movl 12(%esp), %eax / rem, rem 6817c478bd9Sstevel@tonic-gate movl 16(%esp), %edx / rem, rem 6827c478bd9Sstevel@tonic-gate addl $24, %esp 6837c478bd9Sstevel@tonic-gate ret $16 6847c478bd9Sstevel@tonic-gate SET_SIZE(__urem64) 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate/* 6877c478bd9Sstevel@tonic-gate * __div64 6887c478bd9Sstevel@tonic-gate * 6897c478bd9Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the 6907c478bd9Sstevel@tonic-gate * quotient in %edx:%eax. __div64 pops the arguments on return. 6917c478bd9Sstevel@tonic-gate */ 6927c478bd9Sstevel@tonic-gate/ int64_t 6937c478bd9Sstevel@tonic-gate/ __div64(int64_t x, int64_t y) 6947c478bd9Sstevel@tonic-gate/ { 6957c478bd9Sstevel@tonic-gate/ int negative; 6967c478bd9Sstevel@tonic-gate/ uint64_t xt, yt, r; 697*55fea89dSDan Cross/ 6987c478bd9Sstevel@tonic-gate/ if (x < 0) { 6997c478bd9Sstevel@tonic-gate/ xt = -(uint64_t) x; 7007c478bd9Sstevel@tonic-gate/ negative = 1; 7017c478bd9Sstevel@tonic-gate/ } else { 7027c478bd9Sstevel@tonic-gate/ xt = x; 7037c478bd9Sstevel@tonic-gate/ negative = 0; 7047c478bd9Sstevel@tonic-gate/ } 7057c478bd9Sstevel@tonic-gate/ if (y < 0) { 7067c478bd9Sstevel@tonic-gate/ yt = -(uint64_t) y; 7077c478bd9Sstevel@tonic-gate/ negative ^= 1; 7087c478bd9Sstevel@tonic-gate/ } else { 7097c478bd9Sstevel@tonic-gate/ yt = y; 7107c478bd9Sstevel@tonic-gate/ } 7117c478bd9Sstevel@tonic-gate/ r = UDiv(xt, yt); 7127c478bd9Sstevel@tonic-gate/ return (negative ? (int64_t) - r : r); 7137c478bd9Sstevel@tonic-gate/ } 7147c478bd9Sstevel@tonic-gate ENTRY(__div64) 7157c478bd9Sstevel@tonic-gate pushl %ebp 7167c478bd9Sstevel@tonic-gate pushl %edi 7177c478bd9Sstevel@tonic-gate pushl %esi 7187c478bd9Sstevel@tonic-gate subl $8, %esp 7197c478bd9Sstevel@tonic-gate movl 28(%esp), %edx / x, x 7207c478bd9Sstevel@tonic-gate testl %edx, %edx / x 7217c478bd9Sstevel@tonic-gate movl 24(%esp), %eax / x, x 7227c478bd9Sstevel@tonic-gate movl 32(%esp), %esi / y, y 7237c478bd9Sstevel@tonic-gate movl 36(%esp), %edi / y, y 7247c478bd9Sstevel@tonic-gate js .LL84 7257c478bd9Sstevel@tonic-gate xorl %ebp, %ebp / negative 7267c478bd9Sstevel@tonic-gate testl %edi, %edi / y 7277c478bd9Sstevel@tonic-gate movl %eax, (%esp) / x, xt 7287c478bd9Sstevel@tonic-gate movl %edx, 4(%esp) / x, xt 7297c478bd9Sstevel@tonic-gate movl %esi, %eax / y, yt 7307c478bd9Sstevel@tonic-gate movl %edi, %edx / y, yt 7317c478bd9Sstevel@tonic-gate js .LL85 7327c478bd9Sstevel@tonic-gate.LL82: 7337c478bd9Sstevel@tonic-gate pushl %edx / yt 7347c478bd9Sstevel@tonic-gate pushl %eax / yt 7357c478bd9Sstevel@tonic-gate movl 8(%esp), %eax / xt, xt 7367c478bd9Sstevel@tonic-gate movl 12(%esp), %edx / xt, xt 7377c478bd9Sstevel@tonic-gate call UDiv 7387c478bd9Sstevel@tonic-gate popl %ecx 7397c478bd9Sstevel@tonic-gate testl %ebp, %ebp / negative 7407c478bd9Sstevel@tonic-gate popl %esi 7417c478bd9Sstevel@tonic-gate je .LL83 7427c478bd9Sstevel@tonic-gate negl %eax / r 7437c478bd9Sstevel@tonic-gate adcl $0, %edx /, r 7447c478bd9Sstevel@tonic-gate negl %edx / r 7457c478bd9Sstevel@tonic-gate.LL83: 7467c478bd9Sstevel@tonic-gate addl $8, %esp 7477c478bd9Sstevel@tonic-gate popl %esi 7487c478bd9Sstevel@tonic-gate popl %edi 7497c478bd9Sstevel@tonic-gate popl %ebp 7507c478bd9Sstevel@tonic-gate ret $16 7517c478bd9Sstevel@tonic-gate .align 16 7527c478bd9Sstevel@tonic-gate.LL84: 7537c478bd9Sstevel@tonic-gate negl %eax / x 7547c478bd9Sstevel@tonic-gate adcl $0, %edx /, x 7557c478bd9Sstevel@tonic-gate negl %edx / x 7567c478bd9Sstevel@tonic-gate testl %edi, %edi / y 7577c478bd9Sstevel@tonic-gate movl %eax, (%esp) / x, xt 7587c478bd9Sstevel@tonic-gate movl %edx, 4(%esp) / x, xt 7597c478bd9Sstevel@tonic-gate movl $1, %ebp /, negative 7607c478bd9Sstevel@tonic-gate movl %esi, %eax / y, yt 7617c478bd9Sstevel@tonic-gate movl %edi, %edx / y, yt 7627c478bd9Sstevel@tonic-gate jns .LL82 7637c478bd9Sstevel@tonic-gate .align 16 7647c478bd9Sstevel@tonic-gate.LL85: 7657c478bd9Sstevel@tonic-gate negl %eax / yt 7667c478bd9Sstevel@tonic-gate adcl $0, %edx /, yt 7677c478bd9Sstevel@tonic-gate negl %edx / yt 7687c478bd9Sstevel@tonic-gate xorl $1, %ebp /, negative 7697c478bd9Sstevel@tonic-gate jmp .LL82 7707c478bd9Sstevel@tonic-gate SET_SIZE(__div64) 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate/* 7737c478bd9Sstevel@tonic-gate * __rem64 7747c478bd9Sstevel@tonic-gate * 7757c478bd9Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the 7767c478bd9Sstevel@tonic-gate * remainder in %edx:%eax. __rem64 pops the arguments on return. 7777c478bd9Sstevel@tonic-gate */ 7787c478bd9Sstevel@tonic-gate/ int64_t 7797c478bd9Sstevel@tonic-gate/ __rem64(int64_t x, int64_t y) 7807c478bd9Sstevel@tonic-gate/ { 7817c478bd9Sstevel@tonic-gate/ uint64_t xt, yt, rem; 782*55fea89dSDan Cross/ 7837c478bd9Sstevel@tonic-gate/ if (x < 0) { 7847c478bd9Sstevel@tonic-gate/ xt = -(uint64_t) x; 7857c478bd9Sstevel@tonic-gate/ } else { 7867c478bd9Sstevel@tonic-gate/ xt = x; 7877c478bd9Sstevel@tonic-gate/ } 7887c478bd9Sstevel@tonic-gate/ if (y < 0) { 7897c478bd9Sstevel@tonic-gate/ yt = -(uint64_t) y; 7907c478bd9Sstevel@tonic-gate/ } else { 7917c478bd9Sstevel@tonic-gate/ yt = y; 7927c478bd9Sstevel@tonic-gate/ } 7937c478bd9Sstevel@tonic-gate/ (void) UDivRem(xt, yt, &rem); 7947c478bd9Sstevel@tonic-gate/ return (x < 0 ? (int64_t) - rem : rem); 7957c478bd9Sstevel@tonic-gate/ } 7967c478bd9Sstevel@tonic-gate ENTRY(__rem64) 7977c478bd9Sstevel@tonic-gate pushl %edi 7987c478bd9Sstevel@tonic-gate pushl %esi 7997c478bd9Sstevel@tonic-gate subl $20, %esp 8007c478bd9Sstevel@tonic-gate movl 36(%esp), %ecx / x, 8017c478bd9Sstevel@tonic-gate movl 32(%esp), %esi / x, 8027c478bd9Sstevel@tonic-gate movl 36(%esp), %edi / x, 8037c478bd9Sstevel@tonic-gate testl %ecx, %ecx 8047c478bd9Sstevel@tonic-gate movl 40(%esp), %eax / y, y 8057c478bd9Sstevel@tonic-gate movl 44(%esp), %edx / y, y 8067c478bd9Sstevel@tonic-gate movl %esi, (%esp) /, xt 8077c478bd9Sstevel@tonic-gate movl %edi, 4(%esp) /, xt 8087c478bd9Sstevel@tonic-gate js .LL92 8097c478bd9Sstevel@tonic-gate testl %edx, %edx / y 8107c478bd9Sstevel@tonic-gate movl %eax, %esi / y, yt 8117c478bd9Sstevel@tonic-gate movl %edx, %edi / y, yt 8127c478bd9Sstevel@tonic-gate js .LL93 8137c478bd9Sstevel@tonic-gate.LL90: 8147c478bd9Sstevel@tonic-gate leal 8(%esp), %eax /, tmp66 8157c478bd9Sstevel@tonic-gate pushl %eax / tmp66 8167c478bd9Sstevel@tonic-gate pushl %edi / yt 8177c478bd9Sstevel@tonic-gate pushl %esi / yt 8187c478bd9Sstevel@tonic-gate movl 12(%esp), %eax / xt, xt 8197c478bd9Sstevel@tonic-gate movl 16(%esp), %edx / xt, xt 8207c478bd9Sstevel@tonic-gate call UDivRem 8217c478bd9Sstevel@tonic-gate addl $12, %esp 8227c478bd9Sstevel@tonic-gate movl 36(%esp), %edi / x, 8237c478bd9Sstevel@tonic-gate testl %edi, %edi 8247c478bd9Sstevel@tonic-gate movl 8(%esp), %eax / rem, rem 8257c478bd9Sstevel@tonic-gate movl 12(%esp), %edx / rem, rem 8267c478bd9Sstevel@tonic-gate js .LL94 8277c478bd9Sstevel@tonic-gate addl $20, %esp 8287c478bd9Sstevel@tonic-gate popl %esi 8297c478bd9Sstevel@tonic-gate popl %edi 8307c478bd9Sstevel@tonic-gate ret $16 8317c478bd9Sstevel@tonic-gate .align 16 8327c478bd9Sstevel@tonic-gate.LL92: 8337c478bd9Sstevel@tonic-gate negl %esi 8347c478bd9Sstevel@tonic-gate adcl $0, %edi 8357c478bd9Sstevel@tonic-gate negl %edi 8367c478bd9Sstevel@tonic-gate testl %edx, %edx / y 8377c478bd9Sstevel@tonic-gate movl %esi, (%esp) /, xt 8387c478bd9Sstevel@tonic-gate movl %edi, 4(%esp) /, xt 8397c478bd9Sstevel@tonic-gate movl %eax, %esi / y, yt 8407c478bd9Sstevel@tonic-gate movl %edx, %edi / y, yt 8417c478bd9Sstevel@tonic-gate jns .LL90 8427c478bd9Sstevel@tonic-gate .align 16 8437c478bd9Sstevel@tonic-gate.LL93: 8447c478bd9Sstevel@tonic-gate negl %esi / yt 8457c478bd9Sstevel@tonic-gate adcl $0, %edi /, yt 8467c478bd9Sstevel@tonic-gate negl %edi / yt 8477c478bd9Sstevel@tonic-gate jmp .LL90 8487c478bd9Sstevel@tonic-gate .align 16 8497c478bd9Sstevel@tonic-gate.LL94: 8507c478bd9Sstevel@tonic-gate negl %eax / rem 8517c478bd9Sstevel@tonic-gate adcl $0, %edx /, rem 8527c478bd9Sstevel@tonic-gate addl $20, %esp 8537c478bd9Sstevel@tonic-gate popl %esi 8547c478bd9Sstevel@tonic-gate negl %edx / rem 8557c478bd9Sstevel@tonic-gate popl %edi 8567c478bd9Sstevel@tonic-gate ret $16 8577c478bd9Sstevel@tonic-gate SET_SIZE(__rem64) 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate#endif /* __lint */ 86089518a1cSdmick 86189518a1cSdmick#if defined(__lint) 86289518a1cSdmick 86389518a1cSdmick/* 86489518a1cSdmick * C support for 64-bit modulo and division. 865*55fea89dSDan Cross * GNU routines callable from C (though generated by the compiler). 86689518a1cSdmick * Hand-customized compiler output - see comments for details. 86789518a1cSdmick */ 86889518a1cSdmick/*ARGSUSED*/ 86989518a1cSdmickunsigned long long 87089518a1cSdmick__udivdi3(unsigned long long a, unsigned long long b) 87189518a1cSdmick{ return (0); } 87289518a1cSdmick 87389518a1cSdmick/*ARGSUSED*/ 87489518a1cSdmickunsigned long long 87589518a1cSdmick__umoddi3(unsigned long long a, unsigned long long b) 87689518a1cSdmick{ return (0); } 87789518a1cSdmick 87889518a1cSdmick/*ARGSUSED*/ 87989518a1cSdmicklong long 88089518a1cSdmick__divdi3(long long a, long long b) 88189518a1cSdmick{ return (0); } 88289518a1cSdmick 88389518a1cSdmick/*ARGSUSED*/ 88489518a1cSdmicklong long 88589518a1cSdmick__moddi3(long long a, long long b) 88689518a1cSdmick{ return (0); } 88789518a1cSdmick 88889518a1cSdmick/* ARGSUSED */ 88989518a1cSdmickint64_t __divrem64(int64_t a, int64_t b) 89089518a1cSdmick{ return (0); } 89189518a1cSdmick 89289518a1cSdmick/* ARGSUSED */ 89389518a1cSdmickuint64_t __udivrem64(uint64_t a, uint64_t b) 89489518a1cSdmick{ return (0); } 89589518a1cSdmick 89689518a1cSdmick#else /* __lint */ 89789518a1cSdmick 89889518a1cSdmick/* 89989518a1cSdmick * int32_t/int64_t division/manipulation 90089518a1cSdmick * 90189518a1cSdmick * Hand-customized compiler output: the non-GCC entry points depart from 90289518a1cSdmick * the SYS V ABI by requiring their arguments to be popped, and in the 90389518a1cSdmick * [u]divrem64 cases returning the remainder in %ecx:%esi. Note the 90489518a1cSdmick * compiler-generated use of %edx:%eax for the first argument of 90589518a1cSdmick * internal entry points. 90689518a1cSdmick * 90789518a1cSdmick * Inlines for speed: 90889518a1cSdmick * - counting the number of leading zeros in a word 90989518a1cSdmick * - multiplying two 32-bit numbers giving a 64-bit result 91089518a1cSdmick * - dividing a 64-bit number by a 32-bit number, giving both quotient 91189518a1cSdmick * and remainder 91289518a1cSdmick * - subtracting two 64-bit results 91389518a1cSdmick */ 91489518a1cSdmick/ #define LO(X) ((uint32_t)(X) & 0xffffffff) 91589518a1cSdmick/ #define HI(X) ((uint32_t)((X) >> 32) & 0xffffffff) 91689518a1cSdmick/ #define HILO(H, L) (((uint64_t)(H) << 32) + (L)) 917*55fea89dSDan Cross/ 91889518a1cSdmick/ /* give index of highest bit */ 91989518a1cSdmick/ #define HIBIT(a, r) \ 92089518a1cSdmick/ asm("bsrl %1,%0": "=r"((uint32_t)(r)) : "g" (a)) 921*55fea89dSDan Cross/ 92289518a1cSdmick/ /* multiply two uint32_ts resulting in a uint64_t */ 92389518a1cSdmick/ #define A_MUL32(a, b, lo, hi) \ 92489518a1cSdmick/ asm("mull %2" \ 92589518a1cSdmick/ : "=a"((uint32_t)(lo)), "=d"((uint32_t)(hi)) : "g" (b), "0"(a)) 926*55fea89dSDan Cross/ 92789518a1cSdmick/ /* divide a uint64_t by a uint32_t */ 92889518a1cSdmick/ #define A_DIV32(lo, hi, b, q, r) \ 92989518a1cSdmick/ asm("divl %2" \ 93089518a1cSdmick/ : "=a"((uint32_t)(q)), "=d"((uint32_t)(r)) \ 93189518a1cSdmick/ : "g" (b), "0"((uint32_t)(lo)), "1"((uint32_t)hi)) 932*55fea89dSDan Cross/ 93389518a1cSdmick/ /* subtract two uint64_ts (with borrow) */ 93489518a1cSdmick/ #define A_SUB2(bl, bh, al, ah) \ 93589518a1cSdmick/ asm("subl %4,%0\n\tsbbl %5,%1" \ 93689518a1cSdmick/ : "=&r"((uint32_t)(al)), "=r"((uint32_t)(ah)) \ 93789518a1cSdmick/ : "0"((uint32_t)(al)), "1"((uint32_t)(ah)), "g"((uint32_t)(bl)), \ 93889518a1cSdmick/ "g"((uint32_t)(bh))) 93989518a1cSdmick 94089518a1cSdmick/* 94189518a1cSdmick * __udivdi3 94289518a1cSdmick * 94389518a1cSdmick * Perform division of two unsigned 64-bit quantities, returning the 94489518a1cSdmick * quotient in %edx:%eax. 94589518a1cSdmick */ 94689518a1cSdmick ENTRY(__udivdi3) 94789518a1cSdmick movl 4(%esp), %eax / x, x 94889518a1cSdmick movl 8(%esp), %edx / x, x 94989518a1cSdmick pushl 16(%esp) / y 95089518a1cSdmick pushl 16(%esp) 95189518a1cSdmick call UDiv 95289518a1cSdmick addl $8, %esp 95389518a1cSdmick ret 95489518a1cSdmick SET_SIZE(__udivdi3) 95589518a1cSdmick 95689518a1cSdmick/* 95789518a1cSdmick * __umoddi3 95889518a1cSdmick * 95989518a1cSdmick * Perform division of two unsigned 64-bit quantities, returning the 96089518a1cSdmick * remainder in %edx:%eax. 96189518a1cSdmick */ 96289518a1cSdmick ENTRY(__umoddi3) 96389518a1cSdmick subl $12, %esp 96489518a1cSdmick movl %esp, %ecx /, tmp65 96589518a1cSdmick movl 16(%esp), %eax / x, x 96689518a1cSdmick movl 20(%esp), %edx / x, x 96789518a1cSdmick pushl %ecx / tmp65 96889518a1cSdmick pushl 32(%esp) / y 96989518a1cSdmick pushl 32(%esp) 97089518a1cSdmick call UDivRem 97189518a1cSdmick movl 12(%esp), %eax / rem, rem 97289518a1cSdmick movl 16(%esp), %edx / rem, rem 97389518a1cSdmick addl $24, %esp 97489518a1cSdmick ret 97589518a1cSdmick SET_SIZE(__umoddi3) 97689518a1cSdmick 97789518a1cSdmick/* 97889518a1cSdmick * __divdi3 97989518a1cSdmick * 98089518a1cSdmick * Perform division of two signed 64-bit quantities, returning the 98189518a1cSdmick * quotient in %edx:%eax. 98289518a1cSdmick */ 98389518a1cSdmick/ int64_t 98489518a1cSdmick/ __divdi3(int64_t x, int64_t y) 98589518a1cSdmick/ { 98689518a1cSdmick/ int negative; 98789518a1cSdmick/ uint64_t xt, yt, r; 988*55fea89dSDan Cross/ 98989518a1cSdmick/ if (x < 0) { 99089518a1cSdmick/ xt = -(uint64_t) x; 99189518a1cSdmick/ negative = 1; 99289518a1cSdmick/ } else { 99389518a1cSdmick/ xt = x; 99489518a1cSdmick/ negative = 0; 99589518a1cSdmick/ } 99689518a1cSdmick/ if (y < 0) { 99789518a1cSdmick/ yt = -(uint64_t) y; 99889518a1cSdmick/ negative ^= 1; 99989518a1cSdmick/ } else { 100089518a1cSdmick/ yt = y; 100189518a1cSdmick/ } 100289518a1cSdmick/ r = UDiv(xt, yt); 100389518a1cSdmick/ return (negative ? (int64_t) - r : r); 100489518a1cSdmick/ } 100589518a1cSdmick ENTRY(__divdi3) 100689518a1cSdmick pushl %ebp 100789518a1cSdmick pushl %edi 100889518a1cSdmick pushl %esi 100989518a1cSdmick subl $8, %esp 101089518a1cSdmick movl 28(%esp), %edx / x, x 101189518a1cSdmick testl %edx, %edx / x 101289518a1cSdmick movl 24(%esp), %eax / x, x 101389518a1cSdmick movl 32(%esp), %esi / y, y 101489518a1cSdmick movl 36(%esp), %edi / y, y 101589518a1cSdmick js .LL55 101689518a1cSdmick xorl %ebp, %ebp / negative 101789518a1cSdmick testl %edi, %edi / y 101889518a1cSdmick movl %eax, (%esp) / x, xt 101989518a1cSdmick movl %edx, 4(%esp) / x, xt 102089518a1cSdmick movl %esi, %eax / y, yt 102189518a1cSdmick movl %edi, %edx / y, yt 102289518a1cSdmick js .LL56 102389518a1cSdmick.LL53: 102489518a1cSdmick pushl %edx / yt 102589518a1cSdmick pushl %eax / yt 102689518a1cSdmick movl 8(%esp), %eax / xt, xt 102789518a1cSdmick movl 12(%esp), %edx / xt, xt 102889518a1cSdmick call UDiv 102989518a1cSdmick popl %ecx 103089518a1cSdmick testl %ebp, %ebp / negative 103189518a1cSdmick popl %esi 103289518a1cSdmick je .LL54 103389518a1cSdmick negl %eax / r 103489518a1cSdmick adcl $0, %edx /, r 103589518a1cSdmick negl %edx / r 103689518a1cSdmick.LL54: 103789518a1cSdmick addl $8, %esp 103889518a1cSdmick popl %esi 103989518a1cSdmick popl %edi 104089518a1cSdmick popl %ebp 104189518a1cSdmick ret 104289518a1cSdmick .align 16 104389518a1cSdmick.LL55: 104489518a1cSdmick negl %eax / x 104589518a1cSdmick adcl $0, %edx /, x 104689518a1cSdmick negl %edx / x 104789518a1cSdmick testl %edi, %edi / y 104889518a1cSdmick movl %eax, (%esp) / x, xt 104989518a1cSdmick movl %edx, 4(%esp) / x, xt 105089518a1cSdmick movl $1, %ebp /, negative 105189518a1cSdmick movl %esi, %eax / y, yt 105289518a1cSdmick movl %edi, %edx / y, yt 105389518a1cSdmick jns .LL53 105489518a1cSdmick .align 16 105589518a1cSdmick.LL56: 105689518a1cSdmick negl %eax / yt 105789518a1cSdmick adcl $0, %edx /, yt 105889518a1cSdmick negl %edx / yt 105989518a1cSdmick xorl $1, %ebp /, negative 106089518a1cSdmick jmp .LL53 106189518a1cSdmick SET_SIZE(__divdi3) 106289518a1cSdmick 106389518a1cSdmick/* 106489518a1cSdmick * __moddi3 106589518a1cSdmick * 106689518a1cSdmick * Perform division of two signed 64-bit quantities, returning the 106789518a1cSdmick * quotient in %edx:%eax. 106889518a1cSdmick */ 106989518a1cSdmick/ int64_t 107089518a1cSdmick/ __moddi3(int64_t x, int64_t y) 107189518a1cSdmick/ { 107289518a1cSdmick/ uint64_t xt, yt, rem; 1073*55fea89dSDan Cross/ 107489518a1cSdmick/ if (x < 0) { 107589518a1cSdmick/ xt = -(uint64_t) x; 107689518a1cSdmick/ } else { 107789518a1cSdmick/ xt = x; 107889518a1cSdmick/ } 107989518a1cSdmick/ if (y < 0) { 108089518a1cSdmick/ yt = -(uint64_t) y; 108189518a1cSdmick/ } else { 108289518a1cSdmick/ yt = y; 108389518a1cSdmick/ } 108489518a1cSdmick/ (void) UDivRem(xt, yt, &rem); 108589518a1cSdmick/ return (x < 0 ? (int64_t) - rem : rem); 108689518a1cSdmick/ } 108789518a1cSdmick ENTRY(__moddi3) 108889518a1cSdmick pushl %edi 108989518a1cSdmick pushl %esi 109089518a1cSdmick subl $20, %esp 109189518a1cSdmick movl 36(%esp), %ecx / x, 109289518a1cSdmick movl 32(%esp), %esi / x, 109389518a1cSdmick movl 36(%esp), %edi / x, 109489518a1cSdmick testl %ecx, %ecx 109589518a1cSdmick movl 40(%esp), %eax / y, y 109689518a1cSdmick movl 44(%esp), %edx / y, y 109789518a1cSdmick movl %esi, (%esp) /, xt 109889518a1cSdmick movl %edi, 4(%esp) /, xt 109989518a1cSdmick js .LL63 110089518a1cSdmick testl %edx, %edx / y 110189518a1cSdmick movl %eax, %esi / y, yt 110289518a1cSdmick movl %edx, %edi / y, yt 110389518a1cSdmick js .LL64 110489518a1cSdmick.LL61: 110589518a1cSdmick leal 8(%esp), %eax /, tmp66 110689518a1cSdmick pushl %eax / tmp66 110789518a1cSdmick pushl %edi / yt 110889518a1cSdmick pushl %esi / yt 110989518a1cSdmick movl 12(%esp), %eax / xt, xt 111089518a1cSdmick movl 16(%esp), %edx / xt, xt 111189518a1cSdmick call UDivRem 111289518a1cSdmick addl $12, %esp 111389518a1cSdmick movl 36(%esp), %edi / x, 111489518a1cSdmick testl %edi, %edi 111589518a1cSdmick movl 8(%esp), %eax / rem, rem 111689518a1cSdmick movl 12(%esp), %edx / rem, rem 111789518a1cSdmick js .LL65 111889518a1cSdmick addl $20, %esp 111989518a1cSdmick popl %esi 112089518a1cSdmick popl %edi 112189518a1cSdmick ret 112289518a1cSdmick .align 16 112389518a1cSdmick.LL63: 112489518a1cSdmick negl %esi 112589518a1cSdmick adcl $0, %edi 112689518a1cSdmick negl %edi 112789518a1cSdmick testl %edx, %edx / y 112889518a1cSdmick movl %esi, (%esp) /, xt 112989518a1cSdmick movl %edi, 4(%esp) /, xt 113089518a1cSdmick movl %eax, %esi / y, yt 113189518a1cSdmick movl %edx, %edi / y, yt 113289518a1cSdmick jns .LL61 113389518a1cSdmick .align 16 113489518a1cSdmick.LL64: 113589518a1cSdmick negl %esi / yt 113689518a1cSdmick adcl $0, %edi /, yt 113789518a1cSdmick negl %edi / yt 113889518a1cSdmick jmp .LL61 113989518a1cSdmick .align 16 114089518a1cSdmick.LL65: 114189518a1cSdmick negl %eax / rem 114289518a1cSdmick adcl $0, %edx /, rem 114389518a1cSdmick addl $20, %esp 114489518a1cSdmick popl %esi 114589518a1cSdmick negl %edx / rem 114689518a1cSdmick popl %edi 114789518a1cSdmick ret 114889518a1cSdmick SET_SIZE(__moddi3) 114989518a1cSdmick 115089518a1cSdmick/* 115189518a1cSdmick * __udivrem64 115289518a1cSdmick * 115389518a1cSdmick * Perform division of two unsigned 64-bit quantities, returning the 115489518a1cSdmick * quotient in %edx:%eax, and the remainder in %ecx:%esi. __udivrem64 115589518a1cSdmick * pops the arguments on return. 115689518a1cSdmick */ 115789518a1cSdmick ENTRY(__udivrem64) 115889518a1cSdmick subl $12, %esp 115989518a1cSdmick movl %esp, %ecx /, tmp64 116089518a1cSdmick movl 16(%esp), %eax / x, x 116189518a1cSdmick movl 20(%esp), %edx / x, x 116289518a1cSdmick pushl %ecx / tmp64 116389518a1cSdmick pushl 32(%esp) / y 116489518a1cSdmick pushl 32(%esp) 116589518a1cSdmick call UDivRem 116689518a1cSdmick movl 16(%esp), %ecx / rem, tmp63 116789518a1cSdmick movl 12(%esp), %esi / rem 116889518a1cSdmick addl $24, %esp 116989518a1cSdmick ret $16 117089518a1cSdmick SET_SIZE(__udivrem64) 117189518a1cSdmick 117289518a1cSdmick/* 117389518a1cSdmick * Signed division with remainder. 117489518a1cSdmick */ 117589518a1cSdmick/ int64_t 117689518a1cSdmick/ SDivRem(int64_t x, int64_t y, int64_t * pmod) 117789518a1cSdmick/ { 117889518a1cSdmick/ int negative; 117989518a1cSdmick/ uint64_t xt, yt, r, rem; 1180*55fea89dSDan Cross/ 118189518a1cSdmick/ if (x < 0) { 118289518a1cSdmick/ xt = -(uint64_t) x; 118389518a1cSdmick/ negative = 1; 118489518a1cSdmick/ } else { 118589518a1cSdmick/ xt = x; 118689518a1cSdmick/ negative = 0; 118789518a1cSdmick/ } 118889518a1cSdmick/ if (y < 0) { 118989518a1cSdmick/ yt = -(uint64_t) y; 119089518a1cSdmick/ negative ^= 1; 119189518a1cSdmick/ } else { 119289518a1cSdmick/ yt = y; 119389518a1cSdmick/ } 119489518a1cSdmick/ r = UDivRem(xt, yt, &rem); 119589518a1cSdmick/ *pmod = (x < 0 ? (int64_t) - rem : rem); 119689518a1cSdmick/ return (negative ? (int64_t) - r : r); 119789518a1cSdmick/ } 119889518a1cSdmick ENTRY(SDivRem) 119989518a1cSdmick pushl %ebp 120089518a1cSdmick pushl %edi 120189518a1cSdmick pushl %esi 120289518a1cSdmick subl $24, %esp 120389518a1cSdmick testl %edx, %edx / x 120489518a1cSdmick movl %edx, %edi / x, x 120589518a1cSdmick js .LL73 120689518a1cSdmick movl 44(%esp), %esi / y, 120789518a1cSdmick xorl %ebp, %ebp / negative 120889518a1cSdmick testl %esi, %esi 120989518a1cSdmick movl %edx, 12(%esp) / x, xt 121089518a1cSdmick movl %eax, 8(%esp) / x, xt 121189518a1cSdmick movl 40(%esp), %edx / y, yt 121289518a1cSdmick movl 44(%esp), %ecx / y, yt 121389518a1cSdmick js .LL74 121489518a1cSdmick.LL70: 121589518a1cSdmick leal 16(%esp), %eax /, tmp70 121689518a1cSdmick pushl %eax / tmp70 121789518a1cSdmick pushl %ecx / yt 121889518a1cSdmick pushl %edx / yt 121989518a1cSdmick movl 20(%esp), %eax / xt, xt 122089518a1cSdmick movl 24(%esp), %edx / xt, xt 122189518a1cSdmick call UDivRem 122289518a1cSdmick movl %edx, 16(%esp) /, r 122389518a1cSdmick movl %eax, 12(%esp) /, r 122489518a1cSdmick addl $12, %esp 122589518a1cSdmick testl %edi, %edi / x 122689518a1cSdmick movl 16(%esp), %edx / rem, rem 122789518a1cSdmick movl 20(%esp), %ecx / rem, rem 122889518a1cSdmick js .LL75 122989518a1cSdmick.LL71: 123089518a1cSdmick movl 48(%esp), %edi / pmod, pmod 123189518a1cSdmick testl %ebp, %ebp / negative 123289518a1cSdmick movl %edx, (%edi) / rem,* pmod 123389518a1cSdmick movl %ecx, 4(%edi) / rem, 123489518a1cSdmick movl (%esp), %eax / r, r 123589518a1cSdmick movl 4(%esp), %edx / r, r 123689518a1cSdmick je .LL72 123789518a1cSdmick negl %eax / r 123889518a1cSdmick adcl $0, %edx /, r 123989518a1cSdmick negl %edx / r 124089518a1cSdmick.LL72: 124189518a1cSdmick addl $24, %esp 124289518a1cSdmick popl %esi 124389518a1cSdmick popl %edi 124489518a1cSdmick popl %ebp 124589518a1cSdmick ret 124689518a1cSdmick .align 16 124789518a1cSdmick.LL73: 124889518a1cSdmick negl %eax 124989518a1cSdmick adcl $0, %edx 125089518a1cSdmick movl 44(%esp), %esi / y, 125189518a1cSdmick negl %edx 125289518a1cSdmick testl %esi, %esi 125389518a1cSdmick movl %edx, 12(%esp) /, xt 125489518a1cSdmick movl %eax, 8(%esp) /, xt 125589518a1cSdmick movl $1, %ebp /, negative 125689518a1cSdmick movl 40(%esp), %edx / y, yt 125789518a1cSdmick movl 44(%esp), %ecx / y, yt 125889518a1cSdmick jns .LL70 125989518a1cSdmick .align 16 126089518a1cSdmick.LL74: 126189518a1cSdmick negl %edx / yt 126289518a1cSdmick adcl $0, %ecx /, yt 126389518a1cSdmick negl %ecx / yt 126489518a1cSdmick xorl $1, %ebp /, negative 126589518a1cSdmick jmp .LL70 126689518a1cSdmick .align 16 126789518a1cSdmick.LL75: 126889518a1cSdmick negl %edx / rem 126989518a1cSdmick adcl $0, %ecx /, rem 127089518a1cSdmick negl %ecx / rem 127189518a1cSdmick jmp .LL71 127289518a1cSdmick SET_SIZE(SDivRem) 127389518a1cSdmick 127489518a1cSdmick/* 127589518a1cSdmick * __divrem64 127689518a1cSdmick * 127789518a1cSdmick * Perform division of two signed 64-bit quantities, returning the 127889518a1cSdmick * quotient in %edx:%eax, and the remainder in %ecx:%esi. __divrem64 127989518a1cSdmick * pops the arguments on return. 128089518a1cSdmick */ 128189518a1cSdmick ENTRY(__divrem64) 128289518a1cSdmick subl $20, %esp 128389518a1cSdmick movl %esp, %ecx /, tmp64 128489518a1cSdmick movl 24(%esp), %eax / x, x 128589518a1cSdmick movl 28(%esp), %edx / x, x 128689518a1cSdmick pushl %ecx / tmp64 128789518a1cSdmick pushl 40(%esp) / y 128889518a1cSdmick pushl 40(%esp) 128989518a1cSdmick call SDivRem 129089518a1cSdmick movl 16(%esp), %ecx 129189518a1cSdmick movl 12(%esp),%esi / rem 129289518a1cSdmick addl $32, %esp 129389518a1cSdmick ret $16 129489518a1cSdmick SET_SIZE(__divrem64) 129589518a1cSdmick 129689518a1cSdmick 129789518a1cSdmick#endif /* __lint */ 129889518a1cSdmick 129989518a1cSdmick#endif /* defined(__i386) && !defined(__amd64) */ 1300