2.9
[glibc/nacl-glibc.git] / sysdeps / alpha / ldiv.S
blob0a971a7ed000e947f7995944f3ba4d7831791ae6
1 /* Copyright (C) 1996, 1997, 2001, 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Richard Henderson <rth@tamu.edu>.
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
20 #include "div_libc.h"
22 #undef FRAME
23 #ifdef __alpha_fix__
24 #define FRAME 0
25 #else
26 #define FRAME 16
27 #endif
29 #undef X
30 #undef Y
31 #define X $17
32 #define Y $18
34         .set noat
36         .align 4
37         .globl ldiv
38         .ent ldiv
39 ldiv:
40         .frame sp, FRAME, ra
41 #if FRAME > 0
42         lda     sp, -FRAME(sp)
43 #endif
44 #ifdef PROF
45         .set    macro
46         ldgp    gp, 0(pv)
47         lda     AT, _mcount
48         jsr     AT, (AT), _mcount
49         .set    nomacro
50         .prologue 1
51 #else
52         .prologue 0
53 #endif
55         beq     Y, $divbyzero
56         excb
57         mf_fpcr $f10
59         _ITOFT2 X, $f0, 0, Y, $f1, 8
61         .align  4
62         cvtqt   $f0, $f0
63         cvtqt   $f1, $f1
64         divt/c  $f0, $f1, $f0
65         unop
67         /* Check to see if X fit in the double as an exact value.  */
68         sll     X, (64-53), AT
69         sra     AT, (64-53), AT
70         cmpeq   X, AT, AT
71         beq     AT, $x_big
73         /* If we get here, we're expecting exact results from the division.
74            Do nothing else besides convert and clean up.  */
75         cvttq/c $f0, $f0
76         excb
77         mt_fpcr $f10
78         _FTOIT  $f0, $0, 0
80 $egress:
81         mulq    $0, Y, $1
82         subq    X, $1, $1
84         stq     $0, 0($16)
85         stq     $1, 8($16)
86         mov     $16, $0
88 #if FRAME > 0
89         lda     sp, FRAME(sp)
90 #endif
91         ret
93         .align  4
94 $x_big:
95         /* If we get here, X is large enough that we don't expect exact
96            results, and neither X nor Y got mis-translated for the fp
97            division.  Our task is to take the fp result, figure out how
98            far it's off from the correct result and compute a fixup.  */
100 #define Q       v0              /* quotient */
101 #define R       t0              /* remainder */
102 #define SY      t1              /* scaled Y */
103 #define S       t2              /* scalar */
104 #define QY      t3              /* Q*Y */
106         /* The fixup code below can only handle unsigned values.  */
107         or      X, Y, AT
108         mov     $31, t5
109         blt     AT, $fix_sign_in
110 $fix_sign_in_ret1:
111         cvttq/c $f0, $f0
113         _FTOIT  $f0, Q, 8
114 $fix_sign_in_ret2:
115         mulq    Q, Y, QY
116         excb
117         mt_fpcr $f10
119         .align  4
120         subq    QY, X, R
121         mov     Y, SY
122         mov     1, S
123         bgt     R, $q_high
125 $q_high_ret:
126         subq    X, QY, R
127         mov     Y, SY
128         mov     1, S
129         bgt     R, $q_low
131 $q_low_ret:
132         negq    Q, t4
133         cmovlbs t5, t4, Q
134         br      $egress
136         .align  4
137         /* The quotient that we computed was too large.  We need to reduce
138            it by S such that Y*S >= R.  Obviously the closer we get to the
139            correct value the better, but overshooting high is ok, as we'll
140            fix that up later.  */
142         addq    SY, SY, SY
143         addq    S, S, S
144 $q_high:
145         cmpult  SY, R, AT
146         bne     AT, 0b
148         subq    Q, S, Q
149         unop
150         subq    QY, SY, QY
151         br      $q_high_ret
153         .align  4
154         /* The quotient that we computed was too small.  Divide Y by the 
155            current remainder (R) and add that to the existing quotient (Q).
156            The expectation, of course, is that R is much smaller than X.  */
157         /* Begin with a shift-up loop.  Compute S such that Y*S >= R.  We
158            already have a copy of Y in SY and the value 1 in S.  */
160         addq    SY, SY, SY
161         addq    S, S, S
162 $q_low:
163         cmpult  SY, R, AT
164         bne     AT, 0b
166         /* Shift-down and subtract loop.  Each iteration compares our scaled
167            Y (SY) with the remainder (R); if SY <= R then X is divisible by
168            Y's scalar (S) so add it to the quotient (Q).  */
169 2:      addq    Q, S, t3
170         srl     S, 1, S
171         cmpule  SY, R, AT
172         subq    R, SY, t4
174         cmovne  AT, t3, Q
175         cmovne  AT, t4, R
176         srl     SY, 1, SY
177         bne     S, 2b
179         br      $q_low_ret
181         .align  4
182 $fix_sign_in:
183         /* If we got here, then X|Y is negative.  Need to adjust everything
184            such that we're doing unsigned division in the fixup loop.  */
185         /* T5 is true if result should be negative.  */
186         xor     X, Y, AT
187         cmplt   AT, 0, t5
188         cmplt   X, 0, AT
189         negq    X, t0
191         cmovne  AT, t0, X
192         cmplt   Y, 0, AT
193         negq    Y, t0
195         cmovne  AT, t0, Y
196         blbc    t5, $fix_sign_in_ret1
198         cvttq/c $f0, $f0
199         _FTOIT  $f0, Q, 8
200         .align  3
201         negq    Q, Q
202         br      $fix_sign_in_ret2
204 $divbyzero:
205         mov     a0, v0
206         lda     a0, GEN_INTDIV
207         call_pal PAL_gentrap
208         stq     zero, 0(v0)
209         stq     zero, 8(v0)
211 #if FRAME > 0
212         lda     sp, FRAME(sp)
213 #endif
214         ret
216         .end    ldiv
218 weak_alias (ldiv, lldiv)