]>
Commit | Line | Data |
---|---|---|
ba94a1bb WD |
1 | |
2 | .macro ARM_MOD_BODY dividend, divisor, order, spare | |
3 | ||
4 | #if __LINUX_ARM_ARCH__ >= 5 | |
5 | ||
6 | clz \order, \divisor | |
7 | clz \spare, \dividend | |
8 | sub \order, \order, \spare | |
9 | mov \divisor, \divisor, lsl \order | |
10 | ||
11 | #else | |
12 | ||
13 | mov \order, #0 | |
14 | ||
15 | @ Unless the divisor is very big, shift it up in multiples of | |
16 | @ four bits, since this is the amount of unwinding in the main | |
17 | @ division loop. Continue shifting until the divisor is | |
18 | @ larger than the dividend. | |
19 | 1: cmp \divisor, #0x10000000 | |
20 | cmplo \divisor, \dividend | |
21 | movlo \divisor, \divisor, lsl #4 | |
22 | addlo \order, \order, #4 | |
23 | blo 1b | |
24 | ||
25 | @ For very big divisors, we must shift it a bit at a time, or | |
26 | @ we will be in danger of overflowing. | |
27 | 1: cmp \divisor, #0x80000000 | |
28 | cmplo \divisor, \dividend | |
29 | movlo \divisor, \divisor, lsl #1 | |
30 | addlo \order, \order, #1 | |
31 | blo 1b | |
32 | ||
33 | #endif | |
34 | ||
35 | @ Perform all needed substractions to keep only the reminder. | |
36 | @ Do comparisons in batch of 4 first. | |
37 | subs \order, \order, #3 @ yes, 3 is intended here | |
38 | blt 2f | |
39 | ||
40 | 1: cmp \dividend, \divisor | |
41 | subhs \dividend, \dividend, \divisor | |
42 | cmp \dividend, \divisor, lsr #1 | |
43 | subhs \dividend, \dividend, \divisor, lsr #1 | |
44 | cmp \dividend, \divisor, lsr #2 | |
45 | subhs \dividend, \dividend, \divisor, lsr #2 | |
46 | cmp \dividend, \divisor, lsr #3 | |
47 | subhs \dividend, \dividend, \divisor, lsr #3 | |
48 | cmp \dividend, #1 | |
49 | mov \divisor, \divisor, lsr #4 | |
50 | subges \order, \order, #4 | |
51 | bge 1b | |
52 | ||
53 | tst \order, #3 | |
54 | teqne \dividend, #0 | |
55 | beq 5f | |
56 | ||
57 | @ Either 1, 2 or 3 comparison/substractions are left. | |
58 | 2: cmn \order, #2 | |
59 | blt 4f | |
60 | beq 3f | |
61 | cmp \dividend, \divisor | |
62 | subhs \dividend, \dividend, \divisor | |
63 | mov \divisor, \divisor, lsr #1 | |
64 | 3: cmp \dividend, \divisor | |
65 | subhs \dividend, \dividend, \divisor | |
66 | mov \divisor, \divisor, lsr #1 | |
67 | 4: cmp \dividend, \divisor | |
68 | subhs \dividend, \dividend, \divisor | |
69 | 5: | |
70 | .endm | |
71 | ||
72 | .align 5 | |
73 | .globl __modsi3 | |
74 | __modsi3: | |
75 | cmp r1, #0 | |
76 | beq Ldiv0 | |
77 | rsbmi r1, r1, #0 @ loops below use unsigned. | |
78 | movs ip, r0 @ preserve sign of dividend | |
79 | rsbmi r0, r0, #0 @ if negative make positive | |
80 | subs r2, r1, #1 @ compare divisor with 1 | |
81 | cmpne r0, r1 @ compare dividend with divisor | |
82 | moveq r0, #0 | |
83 | tsthi r1, r2 @ see if divisor is power of 2 | |
84 | andeq r0, r0, r2 | |
85 | bls 10f | |
86 | ||
87 | ARM_MOD_BODY r0, r1, r2, r3 | |
88 | ||
89 | 10: cmp ip, #0 | |
90 | rsbmi r0, r0, #0 | |
91 | mov pc, lr | |
92 | ||
93 | ||
94 | Ldiv0: | |
95 | ||
96 | str lr, [sp, #-4]! | |
97 | bl __div0 | |
98 | mov r0, #0 @ About as wrong as it could be. | |
99 | ldr pc, [sp], #4 |