Merge remote-tracking branch 's5p/for-next'
[linux-2.6/next.git] / arch / arm / lib / lib1funcs.S
blobc562f649734cea40f813c3d6c50b9cffcd619ae9
1 /*
2  * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines
3  *
4  * Author: Nicolas Pitre <nico@fluxnic.net>
5  *   - contributed to gcc-3.4 on Sep 30, 2003
6  *   - adapted for the Linux kernel on Oct 2, 2003
7  */
9 /* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
11 This file is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2, or (at your option) any
14 later version.
16 In addition to the permissions in the GNU General Public License, the
17 Free Software Foundation gives you unlimited permission to link the
18 compiled version of this file into combinations with other programs,
19 and to distribute those combinations without any restriction coming
20 from the use of this file.  (The General Public License restrictions
21 do apply in other respects; for example, they cover modification of
22 the file, and distribution when not linked into a combine
23 executable.)
25 This file is distributed in the hope that it will be useful, but
26 WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28 General Public License for more details.
30 You should have received a copy of the GNU General Public License
31 along with this program; see the file COPYING.  If not, write to
32 the Free Software Foundation, 59 Temple Place - Suite 330,
33 Boston, MA 02111-1307, USA.  */
36 #include <linux/linkage.h>
37 #include <asm/assembler.h>
38 #include <asm/unwind.h>
40 .macro ARM_DIV_BODY dividend, divisor, result, curbit
42 #if __LINUX_ARM_ARCH__ >= 5
44         clz     \curbit, \divisor
45         clz     \result, \dividend
46         sub     \result, \curbit, \result
47         mov     \curbit, #1
48         mov     \divisor, \divisor, lsl \result
49         mov     \curbit, \curbit, lsl \result
50         mov     \result, #0
51         
52 #else
54         @ Initially shift the divisor left 3 bits if possible,
55         @ set curbit accordingly.  This allows for curbit to be located
56         @ at the left end of each 4 bit nibbles in the division loop
57         @ to save one loop in most cases.
58         tst     \divisor, #0xe0000000
59         moveq   \divisor, \divisor, lsl #3
60         moveq   \curbit, #8
61         movne   \curbit, #1
63         @ Unless the divisor is very big, shift it up in multiples of
64         @ four bits, since this is the amount of unwinding in the main
65         @ division loop.  Continue shifting until the divisor is 
66         @ larger than the dividend.
67 1:      cmp     \divisor, #0x10000000
68         cmplo   \divisor, \dividend
69         movlo   \divisor, \divisor, lsl #4
70         movlo   \curbit, \curbit, lsl #4
71         blo     1b
73         @ For very big divisors, we must shift it a bit at a time, or
74         @ we will be in danger of overflowing.
75 1:      cmp     \divisor, #0x80000000
76         cmplo   \divisor, \dividend
77         movlo   \divisor, \divisor, lsl #1
78         movlo   \curbit, \curbit, lsl #1
79         blo     1b
81         mov     \result, #0
83 #endif
85         @ Division loop
86 1:      cmp     \dividend, \divisor
87         subhs   \dividend, \dividend, \divisor
88         orrhs   \result,   \result,   \curbit
89         cmp     \dividend, \divisor,  lsr #1
90         subhs   \dividend, \dividend, \divisor, lsr #1
91         orrhs   \result,   \result,   \curbit,  lsr #1
92         cmp     \dividend, \divisor,  lsr #2
93         subhs   \dividend, \dividend, \divisor, lsr #2
94         orrhs   \result,   \result,   \curbit,  lsr #2
95         cmp     \dividend, \divisor,  lsr #3
96         subhs   \dividend, \dividend, \divisor, lsr #3
97         orrhs   \result,   \result,   \curbit,  lsr #3
98         cmp     \dividend, #0                   @ Early termination?
99         movnes  \curbit,   \curbit,  lsr #4     @ No, any more bits to do?
100         movne   \divisor,  \divisor, lsr #4
101         bne     1b
103 .endm
106 .macro ARM_DIV2_ORDER divisor, order
108 #if __LINUX_ARM_ARCH__ >= 5
110         clz     \order, \divisor
111         rsb     \order, \order, #31
113 #else
115         cmp     \divisor, #(1 << 16)
116         movhs   \divisor, \divisor, lsr #16
117         movhs   \order, #16
118         movlo   \order, #0
120         cmp     \divisor, #(1 << 8)
121         movhs   \divisor, \divisor, lsr #8
122         addhs   \order, \order, #8
124         cmp     \divisor, #(1 << 4)
125         movhs   \divisor, \divisor, lsr #4
126         addhs   \order, \order, #4
128         cmp     \divisor, #(1 << 2)
129         addhi   \order, \order, #3
130         addls   \order, \order, \divisor, lsr #1
132 #endif
134 .endm
137 .macro ARM_MOD_BODY dividend, divisor, order, spare
139 #if __LINUX_ARM_ARCH__ >= 5
141         clz     \order, \divisor
142         clz     \spare, \dividend
143         sub     \order, \order, \spare
144         mov     \divisor, \divisor, lsl \order
146 #else
148         mov     \order, #0
150         @ Unless the divisor is very big, shift it up in multiples of
151         @ four bits, since this is the amount of unwinding in the main
152         @ division loop.  Continue shifting until the divisor is 
153         @ larger than the dividend.
154 1:      cmp     \divisor, #0x10000000
155         cmplo   \divisor, \dividend
156         movlo   \divisor, \divisor, lsl #4
157         addlo   \order, \order, #4
158         blo     1b
160         @ For very big divisors, we must shift it a bit at a time, or
161         @ we will be in danger of overflowing.
162 1:      cmp     \divisor, #0x80000000
163         cmplo   \divisor, \dividend
164         movlo   \divisor, \divisor, lsl #1
165         addlo   \order, \order, #1
166         blo     1b
168 #endif
170         @ Perform all needed substractions to keep only the reminder.
171         @ Do comparisons in batch of 4 first.
172         subs    \order, \order, #3              @ yes, 3 is intended here
173         blt     2f
175 1:      cmp     \dividend, \divisor
176         subhs   \dividend, \dividend, \divisor
177         cmp     \dividend, \divisor,  lsr #1
178         subhs   \dividend, \dividend, \divisor, lsr #1
179         cmp     \dividend, \divisor,  lsr #2
180         subhs   \dividend, \dividend, \divisor, lsr #2
181         cmp     \dividend, \divisor,  lsr #3
182         subhs   \dividend, \dividend, \divisor, lsr #3
183         cmp     \dividend, #1
184         mov     \divisor, \divisor, lsr #4
185         subges  \order, \order, #4
186         bge     1b
188         tst     \order, #3
189         teqne   \dividend, #0
190         beq     5f
192         @ Either 1, 2 or 3 comparison/substractions are left.
193 2:      cmn     \order, #2
194         blt     4f
195         beq     3f
196         cmp     \dividend, \divisor
197         subhs   \dividend, \dividend, \divisor
198         mov     \divisor,  \divisor,  lsr #1
199 3:      cmp     \dividend, \divisor
200         subhs   \dividend, \dividend, \divisor
201         mov     \divisor,  \divisor,  lsr #1
202 4:      cmp     \dividend, \divisor
203         subhs   \dividend, \dividend, \divisor
205 .endm
208 ENTRY(__udivsi3)
209 ENTRY(__aeabi_uidiv)
210 UNWIND(.fnstart)
212         subs    r2, r1, #1
213         moveq   pc, lr
214         bcc     Ldiv0
215         cmp     r0, r1
216         bls     11f
217         tst     r1, r2
218         beq     12f
220         ARM_DIV_BODY r0, r1, r2, r3
222         mov     r0, r2
223         mov     pc, lr
225 11:     moveq   r0, #1
226         movne   r0, #0
227         mov     pc, lr
229 12:     ARM_DIV2_ORDER r1, r2
231         mov     r0, r0, lsr r2
232         mov     pc, lr
234 UNWIND(.fnend)
235 ENDPROC(__udivsi3)
236 ENDPROC(__aeabi_uidiv)
238 ENTRY(__umodsi3)
239 UNWIND(.fnstart)
241         subs    r2, r1, #1                      @ compare divisor with 1
242         bcc     Ldiv0
243         cmpne   r0, r1                          @ compare dividend with divisor
244         moveq   r0, #0
245         tsthi   r1, r2                          @ see if divisor is power of 2
246         andeq   r0, r0, r2
247         movls   pc, lr
249         ARM_MOD_BODY r0, r1, r2, r3
251         mov     pc, lr
253 UNWIND(.fnend)
254 ENDPROC(__umodsi3)
256 ENTRY(__divsi3)
257 ENTRY(__aeabi_idiv)
258 UNWIND(.fnstart)
260         cmp     r1, #0
261         eor     ip, r0, r1                      @ save the sign of the result.
262         beq     Ldiv0
263         rsbmi   r1, r1, #0                      @ loops below use unsigned.
264         subs    r2, r1, #1                      @ division by 1 or -1 ?
265         beq     10f
266         movs    r3, r0
267         rsbmi   r3, r0, #0                      @ positive dividend value
268         cmp     r3, r1
269         bls     11f
270         tst     r1, r2                          @ divisor is power of 2 ?
271         beq     12f
273         ARM_DIV_BODY r3, r1, r0, r2
275         cmp     ip, #0
276         rsbmi   r0, r0, #0
277         mov     pc, lr
279 10:     teq     ip, r0                          @ same sign ?
280         rsbmi   r0, r0, #0
281         mov     pc, lr
283 11:     movlo   r0, #0
284         moveq   r0, ip, asr #31
285         orreq   r0, r0, #1
286         mov     pc, lr
288 12:     ARM_DIV2_ORDER r1, r2
290         cmp     ip, #0
291         mov     r0, r3, lsr r2
292         rsbmi   r0, r0, #0
293         mov     pc, lr
295 UNWIND(.fnend)
296 ENDPROC(__divsi3)
297 ENDPROC(__aeabi_idiv)
299 ENTRY(__modsi3)
300 UNWIND(.fnstart)
302         cmp     r1, #0
303         beq     Ldiv0
304         rsbmi   r1, r1, #0                      @ loops below use unsigned.
305         movs    ip, r0                          @ preserve sign of dividend
306         rsbmi   r0, r0, #0                      @ if negative make positive
307         subs    r2, r1, #1                      @ compare divisor with 1
308         cmpne   r0, r1                          @ compare dividend with divisor
309         moveq   r0, #0
310         tsthi   r1, r2                          @ see if divisor is power of 2
311         andeq   r0, r0, r2
312         bls     10f
314         ARM_MOD_BODY r0, r1, r2, r3
316 10:     cmp     ip, #0
317         rsbmi   r0, r0, #0
318         mov     pc, lr
320 UNWIND(.fnend)
321 ENDPROC(__modsi3)
323 #ifdef CONFIG_AEABI
325 ENTRY(__aeabi_uidivmod)
326 UNWIND(.fnstart)
327 UNWIND(.save {r0, r1, ip, lr}   )
329         stmfd   sp!, {r0, r1, ip, lr}
330         bl      __aeabi_uidiv
331         ldmfd   sp!, {r1, r2, ip, lr}
332         mul     r3, r0, r2
333         sub     r1, r1, r3
334         mov     pc, lr
336 UNWIND(.fnend)
337 ENDPROC(__aeabi_uidivmod)
339 ENTRY(__aeabi_idivmod)
340 UNWIND(.fnstart)
341 UNWIND(.save {r0, r1, ip, lr}   )
342         stmfd   sp!, {r0, r1, ip, lr}
343         bl      __aeabi_idiv
344         ldmfd   sp!, {r1, r2, ip, lr}
345         mul     r3, r0, r2
346         sub     r1, r1, r3
347         mov     pc, lr
349 UNWIND(.fnend)
350 ENDPROC(__aeabi_idivmod)
352 #endif
354 Ldiv0:
355 UNWIND(.fnstart)
356 UNWIND(.pad #4)
357 UNWIND(.save {lr})
358         str     lr, [sp, #-8]!
359         bl      __div0
360         mov     r0, #0                  @ About as wrong as it could be.
361         ldr     pc, [sp], #8
362 UNWIND(.fnend)
363 ENDPROC(Ldiv0)