hugetlb: introduce generic version of hugetlb_free_pgd_range
[linux/fpc-iii.git] / arch / x86 / math-emu / div_Xsig.S
blobee08449d20fd80063aeb18398551592f7d3102bd
1 /* SPDX-License-Identifier: GPL-2.0 */
2         .file   "div_Xsig.S"
3 /*---------------------------------------------------------------------------+
4  |  div_Xsig.S                                                               |
5  |                                                                           |
6  | Division subroutine for 96 bit quantities                                 |
7  |                                                                           |
8  | Copyright (C) 1994,1995                                                   |
9  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
10  |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
11  |                                                                           |
12  |                                                                           |
13  +---------------------------------------------------------------------------*/
15 /*---------------------------------------------------------------------------+
16  | Divide the 96 bit quantity pointed to by a, by that pointed to by b, and  |
17  | put the 96 bit result at the location d.                                  |
18  |                                                                           |
19  | The result may not be accurate to 96 bits. It is intended for use where   |
20  | a result better than 64 bits is required. The result should usually be    |
21  | good to at least 94 bits.                                                 |
22  | The returned result is actually divided by one half. This is done to      |
23  | prevent overflow.                                                         |
24  |                                                                           |
25  |  .aaaaaaaaaaaaaa / .bbbbbbbbbbbbb  ->  .dddddddddddd                      |
26  |                                                                           |
27  |  void div_Xsig(Xsig *a, Xsig *b, Xsig *dest)                              |
28  |                                                                           |
29  +---------------------------------------------------------------------------*/
31 #include "exception.h"
32 #include "fpu_emu.h"
35 #define XsigLL(x)       (x)
36 #define XsigL(x)        4(x)
37 #define XsigH(x)        8(x)
40 #ifndef NON_REENTRANT_FPU
42         Local storage on the stack:
43         Accumulator:    FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
44  */
45 #define FPU_accum_3     -4(%ebp)
46 #define FPU_accum_2     -8(%ebp)
47 #define FPU_accum_1     -12(%ebp)
48 #define FPU_accum_0     -16(%ebp)
49 #define FPU_result_3    -20(%ebp)
50 #define FPU_result_2    -24(%ebp)
51 #define FPU_result_1    -28(%ebp)
53 #else
54 .data
56         Local storage in a static area:
57         Accumulator:    FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
58  */
59         .align 4,0
60 FPU_accum_3:
61         .long   0
62 FPU_accum_2:
63         .long   0
64 FPU_accum_1:
65         .long   0
66 FPU_accum_0:
67         .long   0
68 FPU_result_3:
69         .long   0
70 FPU_result_2:
71         .long   0
72 FPU_result_1:
73         .long   0
74 #endif /* NON_REENTRANT_FPU */
77 .text
78 ENTRY(div_Xsig)
79         pushl   %ebp
80         movl    %esp,%ebp
81 #ifndef NON_REENTRANT_FPU
82         subl    $28,%esp
83 #endif /* NON_REENTRANT_FPU */ 
85         pushl   %esi
86         pushl   %edi
87         pushl   %ebx
89         movl    PARAM1,%esi     /* pointer to num */
90         movl    PARAM2,%ebx     /* pointer to denom */
92 #ifdef PARANOID
93         testl   $0x80000000, XsigH(%ebx)        /* Divisor */
94         je      L_bugged
95 #endif /* PARANOID */
98 /*---------------------------------------------------------------------------+
99  |  Divide:   Return  arg1/arg2 to arg3.                                     |
100  |                                                                           |
101  |  The maximum returned value is (ignoring exponents)                       |
102  |               .ffffffff ffffffff                                          |
103  |               ------------------  =  1.ffffffff fffffffe                  |
104  |               .80000000 00000000                                          |
105  | and the minimum is                                                        |
106  |               .80000000 00000000                                          |
107  |               ------------------  =  .80000000 00000001   (rounded)       |
108  |               .ffffffff ffffffff                                          |
109  |                                                                           |
110  +---------------------------------------------------------------------------*/
112         /* Save extended dividend in local register */
114         /* Divide by 2 to prevent overflow */
115         clc
116         movl    XsigH(%esi),%eax
117         rcrl    %eax
118         movl    %eax,FPU_accum_3
119         movl    XsigL(%esi),%eax
120         rcrl    %eax
121         movl    %eax,FPU_accum_2
122         movl    XsigLL(%esi),%eax
123         rcrl    %eax
124         movl    %eax,FPU_accum_1
125         movl    $0,%eax
126         rcrl    %eax
127         movl    %eax,FPU_accum_0
129         movl    FPU_accum_2,%eax        /* Get the current num */
130         movl    FPU_accum_3,%edx
132 /*----------------------------------------------------------------------*/
133 /* Initialization done.
134    Do the first 32 bits. */
136         /* We will divide by a number which is too large */
137         movl    XsigH(%ebx),%ecx
138         addl    $1,%ecx
139         jnc     LFirst_div_not_1
141         /* here we need to divide by 100000000h,
142            i.e., no division at all.. */
143         mov     %edx,%eax
144         jmp     LFirst_div_done
146 LFirst_div_not_1:
147         divl    %ecx            /* Divide the numerator by the augmented
148                                    denom ms dw */
150 LFirst_div_done:
151         movl    %eax,FPU_result_3       /* Put the result in the answer */
153         mull    XsigH(%ebx)     /* mul by the ms dw of the denom */
155         subl    %eax,FPU_accum_2        /* Subtract from the num local reg */
156         sbbl    %edx,FPU_accum_3
158         movl    FPU_result_3,%eax       /* Get the result back */
159         mull    XsigL(%ebx)     /* now mul the ls dw of the denom */
161         subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
162         sbbl    %edx,FPU_accum_2
163         sbbl    $0,FPU_accum_3
164         je      LDo_2nd_32_bits         /* Must check for non-zero result here */
166 #ifdef PARANOID
167         jb      L_bugged_1
168 #endif /* PARANOID */ 
170         /* need to subtract another once of the denom */
171         incl    FPU_result_3    /* Correct the answer */
173         movl    XsigL(%ebx),%eax
174         movl    XsigH(%ebx),%edx
175         subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
176         sbbl    %edx,FPU_accum_2
178 #ifdef PARANOID
179         sbbl    $0,FPU_accum_3
180         jne     L_bugged_1      /* Must check for non-zero result here */
181 #endif /* PARANOID */ 
183 /*----------------------------------------------------------------------*/
184 /* Half of the main problem is done, there is just a reduced numerator
185    to handle now.
186    Work with the second 32 bits, FPU_accum_0 not used from now on */
187 LDo_2nd_32_bits:
188         movl    FPU_accum_2,%edx        /* get the reduced num */
189         movl    FPU_accum_1,%eax
191         /* need to check for possible subsequent overflow */
192         cmpl    XsigH(%ebx),%edx
193         jb      LDo_2nd_div
194         ja      LPrevent_2nd_overflow
196         cmpl    XsigL(%ebx),%eax
197         jb      LDo_2nd_div
199 LPrevent_2nd_overflow:
200 /* The numerator is greater or equal, would cause overflow */
201         /* prevent overflow */
202         subl    XsigL(%ebx),%eax
203         sbbl    XsigH(%ebx),%edx
204         movl    %edx,FPU_accum_2
205         movl    %eax,FPU_accum_1
207         incl    FPU_result_3    /* Reflect the subtraction in the answer */
209 #ifdef PARANOID
210         je      L_bugged_2      /* Can't bump the result to 1.0 */
211 #endif /* PARANOID */ 
213 LDo_2nd_div:
214         cmpl    $0,%ecx         /* augmented denom msw */
215         jnz     LSecond_div_not_1
217         /* %ecx == 0, we are dividing by 1.0 */
218         mov     %edx,%eax
219         jmp     LSecond_div_done
221 LSecond_div_not_1:
222         divl    %ecx            /* Divide the numerator by the denom ms dw */
224 LSecond_div_done:
225         movl    %eax,FPU_result_2       /* Put the result in the answer */
227         mull    XsigH(%ebx)     /* mul by the ms dw of the denom */
229         subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
230         sbbl    %edx,FPU_accum_2
232 #ifdef PARANOID
233         jc      L_bugged_2
234 #endif /* PARANOID */
236         movl    FPU_result_2,%eax       /* Get the result back */
237         mull    XsigL(%ebx)     /* now mul the ls dw of the denom */
239         subl    %eax,FPU_accum_0        /* Subtract from the num local reg */
240         sbbl    %edx,FPU_accum_1        /* Subtract from the num local reg */
241         sbbl    $0,FPU_accum_2
243 #ifdef PARANOID
244         jc      L_bugged_2
245 #endif /* PARANOID */
247         jz      LDo_3rd_32_bits
249 #ifdef PARANOID
250         cmpl    $1,FPU_accum_2
251         jne     L_bugged_2
252 #endif /* PARANOID */ 
254         /* need to subtract another once of the denom */
255         movl    XsigL(%ebx),%eax
256         movl    XsigH(%ebx),%edx
257         subl    %eax,FPU_accum_0        /* Subtract from the num local reg */
258         sbbl    %edx,FPU_accum_1
259         sbbl    $0,FPU_accum_2
261 #ifdef PARANOID
262         jc      L_bugged_2
263         jne     L_bugged_2
264 #endif /* PARANOID */ 
266         addl    $1,FPU_result_2 /* Correct the answer */
267         adcl    $0,FPU_result_3
269 #ifdef PARANOID
270         jc      L_bugged_2      /* Must check for non-zero result here */
271 #endif /* PARANOID */ 
273 /*----------------------------------------------------------------------*/
274 /* The division is essentially finished here, we just need to perform
275    tidying operations.
276    Deal with the 3rd 32 bits */
277 LDo_3rd_32_bits:
278         /* We use an approximation for the third 32 bits.
279         To take account of the 3rd 32 bits of the divisor
280         (call them del), we subtract  del * (a/b) */
282         movl    FPU_result_3,%eax       /* a/b */
283         mull    XsigLL(%ebx)            /* del */
285         subl    %edx,FPU_accum_1
287         /* A borrow indicates that the result is negative */
288         jnb     LTest_over
290         movl    XsigH(%ebx),%edx
291         addl    %edx,FPU_accum_1
293         subl    $1,FPU_result_2         /* Adjust the answer */
294         sbbl    $0,FPU_result_3
296         /* The above addition might not have been enough, check again. */
297         movl    FPU_accum_1,%edx        /* get the reduced num */
298         cmpl    XsigH(%ebx),%edx        /* denom */
299         jb      LDo_3rd_div
301         movl    XsigH(%ebx),%edx
302         addl    %edx,FPU_accum_1
304         subl    $1,FPU_result_2         /* Adjust the answer */
305         sbbl    $0,FPU_result_3
306         jmp     LDo_3rd_div
308 LTest_over:
309         movl    FPU_accum_1,%edx        /* get the reduced num */
311         /* need to check for possible subsequent overflow */
312         cmpl    XsigH(%ebx),%edx        /* denom */
313         jb      LDo_3rd_div
315         /* prevent overflow */
316         subl    XsigH(%ebx),%edx
317         movl    %edx,FPU_accum_1
319         addl    $1,FPU_result_2 /* Reflect the subtraction in the answer */
320         adcl    $0,FPU_result_3
322 LDo_3rd_div:
323         movl    FPU_accum_0,%eax
324         movl    FPU_accum_1,%edx
325         divl    XsigH(%ebx)
327         movl    %eax,FPU_result_1       /* Rough estimate of third word */
329         movl    PARAM3,%esi             /* pointer to answer */
331         movl    FPU_result_1,%eax
332         movl    %eax,XsigLL(%esi)
333         movl    FPU_result_2,%eax
334         movl    %eax,XsigL(%esi)
335         movl    FPU_result_3,%eax
336         movl    %eax,XsigH(%esi)
338 L_exit:
339         popl    %ebx
340         popl    %edi
341         popl    %esi
343         leave
344         ret
347 #ifdef PARANOID
348 /* The logic is wrong if we got here */
349 L_bugged:
350         pushl   EX_INTERNAL|0x240
351         call    EXCEPTION
352         pop     %ebx
353         jmp     L_exit
355 L_bugged_1:
356         pushl   EX_INTERNAL|0x241
357         call    EXCEPTION
358         pop     %ebx
359         jmp     L_exit
361 L_bugged_2:
362         pushl   EX_INTERNAL|0x242
363         call    EXCEPTION
364         pop     %ebx
365         jmp     L_exit
366 #endif /* PARANOID */ 
367 ENDPROC(div_Xsig)