Merge from vendor branch GCC:
[dragonfly.git] / sys / i386 / gnu / fpemul / reg_u_sub.s
1         .file   "reg_u_sub.S"
2 /*
3  *  reg_u_sub.S
4  *
5  * Core floating point subtraction routine.
6  *
7  * Call from C as:
8  *   void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
9  *                                                int control_w)
10  *
11  *
12  * Copyright (C) 1992,1993,1994
13  *                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
14  *                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au
15  * All rights reserved.
16  *
17  * This copyright notice covers the redistribution and use of the
18  * FPU emulator developed by W. Metzenthen. It covers only its use
19  * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
20  * use is not permitted under this copyright.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the above copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must include information specifying
28  *    that source code for the emulator is freely available and include
29  *    either:
30  *      a) an offer to provide the source code for a nominal distribution
31  *         fee, or
32  *      b) list at least two alternative methods whereby the source
33  *         can be obtained, e.g. a publically accessible bulletin board
34  *         and an anonymous ftp site from which the software can be
35  *         downloaded.
36  * 3. All advertising materials specifically mentioning features or use of
37  *    this emulator must acknowledge that it was developed by W. Metzenthen.
38  * 4. The name of W. Metzenthen may not be used to endorse or promote
39  *    products derived from this software without specific prior written
40  *    permission.
41  *
42  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
43  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
44  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
45  * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
46  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
47  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
48  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
49  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
50  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
51  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52  *
53  *
54  * The purpose of this copyright, based upon the Berkeley copyright, is to
55  * ensure that the covered software remains freely available to everyone.
56  *
57  * The software (with necessary differences) is also available, but under
58  * the terms of the GNU copyleft, for the Linux operating system and for
59  * the djgpp ms-dos extender.
60  *
61  * W. Metzenthen   June 1994.
62  *
63  *
64  * $FreeBSD: src/sys/gnu/i386/fpemul/reg_u_sub.s,v 1.9 1999/08/28 00:42:58 peter Exp $
65  * $DragonFly: src/sys/i386/gnu/fpemul/Attic/reg_u_sub.s,v 1.4 2003/08/07 21:17:21 dillon Exp $
66  *
67  */
68
69 /*
70  |    Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
71  |    Takes two valid reg f.p. numbers (TW_Valid), which are
72  |    treated as unsigned numbers,
73  |    and returns their difference as a TW_Valid or TW_Zero f.p.
74  |    number.
75  |    The first number (arg1) must be the larger.
76  |    The returned number is normalized.
77  |    Basic checks are performed if PARANOID is defined.
78  */
79
80 #include "fpu_asm.h"
81
82 .text
83 ENTRY(reg_u_sub)
84         pushl   %ebp
85         movl    %esp,%ebp
86         pushl   %esi
87         pushl   %edi
88         pushl   %ebx
89
90         movl    PARAM1,%esi     /* source 1 */
91         movl    PARAM2,%edi     /* source 2 */
92
93 #ifdef DENORM_OPERAND
94         cmpl    EXP_UNDER,EXP(%esi)
95         jg      xOp1_not_denorm
96
97         call    denormal_operand
98         orl     %eax,%eax
99         jnz     FPU_Arith_exit
100
101 xOp1_not_denorm:
102         cmpl    EXP_UNDER,EXP(%edi)
103         jg      xOp2_not_denorm
104
105         call    denormal_operand
106         orl     %eax,%eax
107         jnz     FPU_Arith_exit
108
109 xOp2_not_denorm:
110 #endif DENORM_OPERAND
111
112 /*      xorl    %ecx,%ecx */
113         movl    EXP(%esi),%ecx
114         subl    EXP(%edi),%ecx  /* exp1 - exp2 */
115
116 #ifdef PARANOID
117         /* source 2 is always smaller than source 1 */
118 /*      jc      L_bugged */
119         js      L_bugged_1
120
121         testl   $0x80000000,SIGH(%edi)  /* The args are assumed to be be normalized */
122         je      L_bugged_2
123
124         testl   $0x80000000,SIGH(%esi)
125         je      L_bugged_2
126 #endif PARANOID
127
128 /*--------------------------------------+
129  |      Form a register holding the     |
130  |      smaller number                  |
131  +--------------------------------------*/
132         movl    SIGH(%edi),%eax /* register ms word */
133         movl    SIGL(%edi),%ebx /* register ls word */
134
135         movl    PARAM3,%edi     /* destination */
136         movl    EXP(%esi),%edx
137         movl    %edx,EXP(%edi)  /* Copy exponent to destination */
138         movb    SIGN(%esi),%dl
139         movb    %dl,SIGN(%edi)  /* Copy the sign from the first arg */
140
141         xorl    %edx,%edx       /* register extension */
142
143 /*--------------------------------------+
144  |      Shift the temporary register    |
145  |      right the required number of    |
146  |      places.                         |
147  +--------------------------------------*/
148 L_shift_r:
149         cmpl    $32,%ecx                /* shrd only works for 0..31 bits */
150         jnc     L_more_than_31
151
152 /* less than 32 bits */
153         shrd    %cl,%ebx,%edx
154         shrd    %cl,%eax,%ebx
155         shr     %cl,%eax
156         jmp     L_shift_done
157
158 L_more_than_31:
159         cmpl    $64,%ecx
160         jnc     L_more_than_63
161
162         subb    $32,%cl
163         jz      L_exactly_32
164
165         shrd    %cl,%eax,%edx
166         shr     %cl,%eax
167         orl     %ebx,%ebx
168         jz      L_more_31_no_low        /* none of the lowest bits is set */
169
170         orl     $1,%edx                 /* record the fact in the extension */
171
172 L_more_31_no_low:
173         movl    %eax,%ebx
174         xorl    %eax,%eax
175         jmp     L_shift_done
176
177 L_exactly_32:
178         movl    %ebx,%edx
179         movl    %eax,%ebx
180         xorl    %eax,%eax
181         jmp     L_shift_done
182
183 L_more_than_63:
184         cmpw    $65,%cx
185         jnc     L_more_than_64
186
187         /* Shift right by 64 bits */
188         movl    %eax,%edx
189         orl     %ebx,%ebx
190         jz      L_more_63_no_low
191
192         orl     $1,%edx
193         jmp     L_more_63_no_low
194
195 L_more_than_64:
196         jne     L_more_than_65
197
198         /* Shift right by 65 bits */
199         /* Carry is clear if we get here */
200         movl    %eax,%edx
201         rcrl    %edx
202         jnc     L_shift_65_nc
203
204         orl     $1,%edx
205         jmp     L_more_63_no_low
206
207 L_shift_65_nc:
208         orl     %ebx,%ebx
209         jz      L_more_63_no_low
210
211         orl     $1,%edx
212         jmp     L_more_63_no_low
213
214 L_more_than_65:
215         movl    $1,%edx         /* The shifted nr always at least one '1' */
216
217 L_more_63_no_low:
218         xorl    %ebx,%ebx
219         xorl    %eax,%eax
220
221 L_shift_done:
222 L_subtr:
223 /*------------------------------+
224  |      Do the subtraction      |
225  +------------------------------*/
226         xorl    %ecx,%ecx
227         subl    %edx,%ecx
228         movl    %ecx,%edx
229         movl    SIGL(%esi),%ecx
230         sbbl    %ebx,%ecx
231         movl    %ecx,%ebx
232         movl    SIGH(%esi),%ecx
233         sbbl    %eax,%ecx
234         movl    %ecx,%eax
235
236 #ifdef PARANOID
237         /* We can never get a borrow */
238         jc      L_bugged
239 #endif PARANOID
240
241 /*--------------------------------------+
242  |      Normalize the result            |
243  +--------------------------------------*/
244         testl   $0x80000000,%eax
245         jnz     L_round         /* no shifting needed */
246
247         orl     %eax,%eax
248         jnz     L_shift_1       /* shift left 1 - 31 bits */
249
250         orl     %ebx,%ebx
251         jnz     L_shift_32      /* shift left 32 - 63 bits */
252
253 /*       A rare case, the only one which is non-zero if we got here
254 //         is:           1000000 .... 0000
255 //                      -0111111 .... 1111 1
256 //                       -------------------- 
257 //                       0000000 .... 0000 1  */
258
259         cmpl    $0x80000000,%edx
260         jnz     L_must_be_zero
261
262         /* Shift left 64 bits */
263         subl    $64,EXP(%edi)
264         movl    %edx,%eax
265         jmp     L_store
266
267 L_must_be_zero:
268 #ifdef PARANOID
269         orl     %edx,%edx
270         jnz     L_bugged_3
271 #endif PARANOID
272
273         /* The result is zero */
274         movb    TW_Zero,TAG(%edi)
275         movl    $0,EXP(%edi)            /* exponent */
276         movl    $0,SIGL(%edi)
277         movl    $0,SIGH(%edi)
278         jmp     L_exit          /* Does not underflow */
279
280 L_shift_32:
281         movl    %ebx,%eax
282         movl    %edx,%ebx
283         movl    $0,%edx
284         subl    $32,EXP(%edi)   /* Can get underflow here */
285
286 /* We need to shift left by 1 - 31 bits */
287 L_shift_1:
288         bsrl    %eax,%ecx       /* get the required shift in %ecx */
289         subl    $31,%ecx
290         negl    %ecx
291         shld    %cl,%ebx,%eax
292         shld    %cl,%edx,%ebx
293         shl     %cl,%edx
294         subl    %ecx,EXP(%edi)  /* Can get underflow here */
295
296 L_round:
297         jmp     FPU_round       /* Round the result */
298
299
300 #ifdef PARANOID
301 L_bugged_1:
302         pushl   EX_INTERNAL|0x206
303         call    EXCEPTION
304         pop     %ebx
305         jmp     L_exit
306
307 L_bugged_2:
308         pushl   EX_INTERNAL|0x209
309         call    EXCEPTION
310         pop     %ebx
311         jmp     L_exit
312
313 L_bugged_3:
314         pushl   EX_INTERNAL|0x210
315         call    EXCEPTION
316         pop     %ebx
317         jmp     L_exit
318
319 L_bugged_4:
320         pushl   EX_INTERNAL|0x211
321         call    EXCEPTION
322         pop     %ebx
323         jmp     L_exit
324
325 L_bugged:
326         pushl   EX_INTERNAL|0x212
327         call    EXCEPTION
328         pop     %ebx
329         jmp     L_exit
330 #endif PARANOID
331
332
333 L_store:
334 /*------------------------------+
335  |      Store the result        |
336  +------------------------------*/
337         movl    %eax,SIGH(%edi)
338         movl    %ebx,SIGL(%edi)
339
340         movb    TW_Valid,TAG(%edi)              /* Set the tags to TW_Valid */
341
342         cmpl    EXP_UNDER,EXP(%edi)
343         jle     L_underflow
344
345 L_exit:
346         popl    %ebx
347         popl    %edi
348         popl    %esi
349         leave
350         ret
351
352
353 L_underflow:
354         push    %edi
355         call    arith_underflow
356         pop     %ebx
357         jmp     L_exit
358