Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm/lib/div64.S
26295 views
1
/* SPDX-License-Identifier: GPL-2.0-only */
2
/*
3
* linux/arch/arm/lib/div64.S
4
*
5
* Optimized computation of 64-bit dividend / 32-bit divisor
6
*
7
* Author: Nicolas Pitre
8
* Created: Oct 5, 2003
9
* Copyright: Monta Vista Software, Inc.
10
*/
11
12
#include <linux/linkage.h>
13
#include <asm/assembler.h>
14
#include <asm/unwind.h>
15
16
#ifdef __ARMEB__
17
#define xh r0
18
#define xl r1
19
#define yh r2
20
#define yl r3
21
#else
22
#define xl r0
23
#define xh r1
24
#define yl r2
25
#define yh r3
26
#endif
27
28
/*
29
* __do_div64: perform a division with 64-bit dividend and 32-bit divisor.
30
*
31
* Note: Calling convention is totally non standard for optimal code.
32
* This is meant to be used by do_div() from include/asm/div64.h only.
33
*
34
* Input parameters:
35
* xh-xl = dividend (clobbered)
36
* r4 = divisor (preserved)
37
*
38
* Output values:
39
* yh-yl = result
40
* xh = remainder
41
*
42
* Clobbered regs: xl, ip
43
*/
44
45
ENTRY(__do_div64)
46
UNWIND(.fnstart)
47
48
@ Test for easy paths first.
49
subs ip, r4, #1
50
bls 9f @ divisor is 0 or 1
51
tst ip, r4
52
beq 8f @ divisor is power of 2
53
54
@ See if we need to handle upper 32-bit result.
55
cmp xh, r4
56
mov yh, #0
57
blo 3f
58
59
@ Align divisor with upper part of dividend.
60
@ The aligned divisor is stored in yl preserving the original.
61
@ The bit position is stored in ip.
62
63
#if __LINUX_ARM_ARCH__ >= 5
64
65
clz yl, r4
66
clz ip, xh
67
sub yl, yl, ip
68
mov ip, #1
69
mov ip, ip, lsl yl
70
mov yl, r4, lsl yl
71
72
#else
73
74
mov yl, r4
75
mov ip, #1
76
1: cmp yl, #0x80000000
77
cmpcc yl, xh
78
movcc yl, yl, lsl #1
79
movcc ip, ip, lsl #1
80
bcc 1b
81
82
#endif
83
84
@ The division loop for needed upper bit positions.
85
@ Break out early if dividend reaches 0.
86
2: cmp xh, yl
87
orrcs yh, yh, ip
88
subscs xh, xh, yl
89
movsne ip, ip, lsr #1
90
mov yl, yl, lsr #1
91
bne 2b
92
93
@ See if we need to handle lower 32-bit result.
94
3: cmp xh, #0
95
mov yl, #0
96
cmpeq xl, r4
97
movlo xh, xl
98
retlo lr
99
100
@ The division loop for lower bit positions.
101
@ Here we shift remainer bits leftwards rather than moving the
102
@ divisor for comparisons, considering the carry-out bit as well.
103
mov ip, #0x80000000
104
4: movs xl, xl, lsl #1
105
adcs xh, xh, xh
106
beq 6f
107
cmpcc xh, r4
108
5: orrcs yl, yl, ip
109
subcs xh, xh, r4
110
movs ip, ip, lsr #1
111
bne 4b
112
ret lr
113
114
@ The top part of remainder became zero. If carry is set
115
@ (the 33th bit) this is a false positive so resume the loop.
116
@ Otherwise, if lower part is also null then we are done.
117
6: bcs 5b
118
cmp xl, #0
119
reteq lr
120
121
@ We still have remainer bits in the low part. Bring them up.
122
123
#if __LINUX_ARM_ARCH__ >= 5
124
125
clz xh, xl @ we know xh is zero here so...
126
add xh, xh, #1
127
mov xl, xl, lsl xh
128
mov ip, ip, lsr xh
129
130
#else
131
132
7: movs xl, xl, lsl #1
133
mov ip, ip, lsr #1
134
bcc 7b
135
136
#endif
137
138
@ Current remainder is now 1. It is worthless to compare with
139
@ divisor at this point since divisor can not be smaller than 3 here.
140
@ If possible, branch for another shift in the division loop.
141
@ If no bit position left then we are done.
142
movs ip, ip, lsr #1
143
mov xh, #1
144
bne 4b
145
ret lr
146
147
8: @ Division by a power of 2: determine what that divisor order is
148
@ then simply shift values around
149
150
#if __LINUX_ARM_ARCH__ >= 5
151
152
clz ip, r4
153
rsb ip, ip, #31
154
155
#else
156
157
mov yl, r4
158
cmp r4, #(1 << 16)
159
mov ip, #0
160
movhs yl, yl, lsr #16
161
movhs ip, #16
162
163
cmp yl, #(1 << 8)
164
movhs yl, yl, lsr #8
165
addhs ip, ip, #8
166
167
cmp yl, #(1 << 4)
168
movhs yl, yl, lsr #4
169
addhs ip, ip, #4
170
171
cmp yl, #(1 << 2)
172
addhi ip, ip, #3
173
addls ip, ip, yl, lsr #1
174
175
#endif
176
177
mov yh, xh, lsr ip
178
mov yl, xl, lsr ip
179
rsb ip, ip, #32
180
ARM( orr yl, yl, xh, lsl ip )
181
THUMB( lsl xh, xh, ip )
182
THUMB( orr yl, yl, xh )
183
mov xh, xl, lsl ip
184
mov xh, xh, lsr ip
185
ret lr
186
187
@ eq -> division by 1: obvious enough...
188
9: moveq yl, xl
189
moveq yh, xh
190
moveq xh, #0
191
reteq lr
192
UNWIND(.fnend)
193
194
UNWIND(.fnstart)
195
UNWIND(.pad #4)
196
UNWIND(.save {lr})
197
Ldiv0_64:
198
@ Division by 0:
199
str lr, [sp, #-8]!
200
bl __div0
201
202
@ as wrong as it could be...
203
mov yl, #0
204
mov yh, #0
205
mov xh, #0
206
ldr pc, [sp], #8
207
208
UNWIND(.fnend)
209
ENDPROC(__do_div64)
210
211