diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-08-02 05:55:55 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-08-02 16:32:35 -0400 |
commit | 4baa9922430662431231ac637adedddbb0cfb2d7 (patch) | |
tree | e8fb765ce3e41c01f33de34a0bc9494f0ae19818 /arch/arm/include/asm/div64.h | |
parent | ff4db0a043a5dee7180bdffd178e61cd02812c68 (diff) |
[ARM] move include/asm-arm to arch/arm/include/asm
Move platform independent header files to arch/arm/include/asm, leaving
those in asm/arch* and asm/plat* alone.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/include/asm/div64.h')
-rw-r--r-- | arch/arm/include/asm/div64.h | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/arch/arm/include/asm/div64.h b/arch/arm/include/asm/div64.h new file mode 100644 index 000000000000..5001390be958 --- /dev/null +++ b/arch/arm/include/asm/div64.h | |||
@@ -0,0 +1,227 @@ | |||
1 | #ifndef __ASM_ARM_DIV64 | ||
2 | #define __ASM_ARM_DIV64 | ||
3 | |||
4 | #include <asm/system.h> | ||
5 | #include <linux/types.h> | ||
6 | |||
7 | /* | ||
8 | * The semantics of do_div() are: | ||
9 | * | ||
10 | * uint32_t do_div(uint64_t *n, uint32_t base) | ||
11 | * { | ||
12 | * uint32_t remainder = *n % base; | ||
13 | * *n = *n / base; | ||
14 | * return remainder; | ||
15 | * } | ||
16 | * | ||
17 | * In other words, a 64-bit dividend with a 32-bit divisor producing | ||
18 | * a 64-bit result and a 32-bit remainder. To accomplish this optimally | ||
19 | * we call a special __do_div64 helper with completely non standard | ||
20 | * calling convention for arguments and results (beware). | ||
21 | */ | ||
22 | |||
23 | #ifdef __ARMEB__ | ||
24 | #define __xh "r0" | ||
25 | #define __xl "r1" | ||
26 | #else | ||
27 | #define __xl "r0" | ||
28 | #define __xh "r1" | ||
29 | #endif | ||
30 | |||
31 | #define __do_div_asm(n, base) \ | ||
32 | ({ \ | ||
33 | register unsigned int __base asm("r4") = base; \ | ||
34 | register unsigned long long __n asm("r0") = n; \ | ||
35 | register unsigned long long __res asm("r2"); \ | ||
36 | register unsigned int __rem asm(__xh); \ | ||
37 | asm( __asmeq("%0", __xh) \ | ||
38 | __asmeq("%1", "r2") \ | ||
39 | __asmeq("%2", "r0") \ | ||
40 | __asmeq("%3", "r4") \ | ||
41 | "bl __do_div64" \ | ||
42 | : "=r" (__rem), "=r" (__res) \ | ||
43 | : "r" (__n), "r" (__base) \ | ||
44 | : "ip", "lr", "cc"); \ | ||
45 | n = __res; \ | ||
46 | __rem; \ | ||
47 | }) | ||
48 | |||
49 | #if __GNUC__ < 4 | ||
50 | |||
51 | /* | ||
52 | * gcc versions earlier than 4.0 are simply too problematic for the | ||
53 | * optimized implementation below. First there is gcc PR 15089 that | ||
54 | * tend to trig on more complex constructs, spurious .global __udivsi3 | ||
55 | * are inserted even if none of those symbols are referenced in the | ||
56 | * generated code, and those gcc versions are not able to do constant | ||
57 | * propagation on long long values anyway. | ||
58 | */ | ||
59 | #define do_div(n, base) __do_div_asm(n, base) | ||
60 | |||
61 | #elif __GNUC__ >= 4 | ||
62 | |||
63 | #include <asm/bug.h> | ||
64 | |||
65 | /* | ||
66 | * If the divisor happens to be constant, we determine the appropriate | ||
67 | * inverse at compile time to turn the division into a few inline | ||
68 | * multiplications instead which is much faster. And yet only if compiling | ||
69 | * for ARMv4 or higher (we need umull/umlal) and if the gcc version is | ||
70 | * sufficiently recent to perform proper long long constant propagation. | ||
71 | * (It is unfortunate that gcc doesn't perform all this internally.) | ||
72 | */ | ||
73 | #define do_div(n, base) \ | ||
74 | ({ \ | ||
75 | unsigned int __r, __b = (base); \ | ||
76 | if (!__builtin_constant_p(__b) || __b == 0 || \ | ||
77 | (__LINUX_ARM_ARCH__ < 4 && (__b & (__b - 1)) != 0)) { \ | ||
78 | /* non-constant divisor (or zero): slow path */ \ | ||
79 | __r = __do_div_asm(n, __b); \ | ||
80 | } else if ((__b & (__b - 1)) == 0) { \ | ||
81 | /* Trivial: __b is constant and a power of 2 */ \ | ||
82 | /* gcc does the right thing with this code. */ \ | ||
83 | __r = n; \ | ||
84 | __r &= (__b - 1); \ | ||
85 | n /= __b; \ | ||
86 | } else { \ | ||
87 | /* Multiply by inverse of __b: n/b = n*(p/b)/p */ \ | ||
88 | /* We rely on the fact that most of this code gets */ \ | ||
89 | /* optimized away at compile time due to constant */ \ | ||
90 | /* propagation and only a couple inline assembly */ \ | ||
91 | /* instructions should remain. Better avoid any */ \ | ||
92 | /* code construct that might prevent that. */ \ | ||
93 | unsigned long long __res, __x, __t, __m, __n = n; \ | ||
94 | unsigned int __c, __p, __z = 0; \ | ||
95 | /* preserve low part of n for reminder computation */ \ | ||
96 | __r = __n; \ | ||
97 | /* determine number of bits to represent __b */ \ | ||
98 | __p = 1 << __div64_fls(__b); \ | ||
99 | /* compute __m = ((__p << 64) + __b - 1) / __b */ \ | ||
100 | __m = (~0ULL / __b) * __p; \ | ||
101 | __m += (((~0ULL % __b + 1) * __p) + __b - 1) / __b; \ | ||
102 | /* compute __res = __m*(~0ULL/__b*__b-1)/(__p << 64) */ \ | ||
103 | __x = ~0ULL / __b * __b - 1; \ | ||
104 | __res = (__m & 0xffffffff) * (__x & 0xffffffff); \ | ||
105 | __res >>= 32; \ | ||
106 | __res += (__m & 0xffffffff) * (__x >> 32); \ | ||
107 | __t = __res; \ | ||
108 | __res += (__x & 0xffffffff) * (__m >> 32); \ | ||
109 | __t = (__res < __t) ? (1ULL << 32) : 0; \ | ||
110 | __res = (__res >> 32) + __t; \ | ||
111 | __res += (__m >> 32) * (__x >> 32); \ | ||
112 | __res /= __p; \ | ||
113 | /* Now sanitize and optimize what we've got. */ \ | ||
114 | if (~0ULL % (__b / (__b & -__b)) == 0) { \ | ||
115 | /* those cases can be simplified with: */ \ | ||
116 | __n /= (__b & -__b); \ | ||
117 | __m = ~0ULL / (__b / (__b & -__b)); \ | ||
118 | __p = 1; \ | ||
119 | __c = 1; \ | ||
120 | } else if (__res != __x / __b) { \ | ||
121 | /* We can't get away without a correction */ \ | ||
122 | /* to compensate for bit truncation errors. */ \ | ||
123 | /* To avoid it we'd need an additional bit */ \ | ||
124 | /* to represent __m which would overflow it. */ \ | ||
125 | /* Instead we do m=p/b and n/b=(n*m+m)/p. */ \ | ||
126 | __c = 1; \ | ||
127 | /* Compute __m = (__p << 64) / __b */ \ | ||
128 | __m = (~0ULL / __b) * __p; \ | ||
129 | __m += ((~0ULL % __b + 1) * __p) / __b; \ | ||
130 | } else { \ | ||
131 | /* Reduce __m/__p, and try to clear bit 31 */ \ | ||
132 | /* of __m when possible otherwise that'll */ \ | ||
133 | /* need extra overflow handling later. */ \ | ||
134 | unsigned int __bits = -(__m & -__m); \ | ||
135 | __bits |= __m >> 32; \ | ||
136 | __bits = (~__bits) << 1; \ | ||
137 | /* If __bits == 0 then setting bit 31 is */ \ | ||
138 | /* unavoidable. Simply apply the maximum */ \ | ||
139 | /* possible reduction in that case. */ \ | ||
140 | /* Otherwise the MSB of __bits indicates the */ \ | ||
141 | /* best reduction we should apply. */ \ | ||
142 | if (!__bits) { \ | ||
143 | __p /= (__m & -__m); \ | ||
144 | __m /= (__m & -__m); \ | ||
145 | } else { \ | ||
146 | __p >>= __div64_fls(__bits); \ | ||
147 | __m >>= __div64_fls(__bits); \ | ||
148 | } \ | ||
149 | /* No correction needed. */ \ | ||
150 | __c = 0; \ | ||
151 | } \ | ||
152 | /* Now we have a combination of 2 conditions: */ \ | ||
153 | /* 1) whether or not we need a correction (__c), and */ \ | ||
154 | /* 2) whether or not there might be an overflow in */ \ | ||
155 | /* the cross product (__m & ((1<<63) | (1<<31))) */ \ | ||
156 | /* Select the best insn combination to perform the */ \ | ||
157 | /* actual __m * __n / (__p << 64) operation. */ \ | ||
158 | if (!__c) { \ | ||
159 | asm ( "umull %Q0, %R0, %1, %Q2\n\t" \ | ||
160 | "mov %Q0, #0" \ | ||
161 | : "=&r" (__res) \ | ||
162 | : "r" (__m), "r" (__n) \ | ||
163 | : "cc" ); \ | ||
164 | } else if (!(__m & ((1ULL << 63) | (1ULL << 31)))) { \ | ||
165 | __res = __m; \ | ||
166 | asm ( "umlal %Q0, %R0, %Q1, %Q2\n\t" \ | ||
167 | "mov %Q0, #0" \ | ||
168 | : "+r" (__res) \ | ||
169 | : "r" (__m), "r" (__n) \ | ||
170 | : "cc" ); \ | ||
171 | } else { \ | ||
172 | asm ( "umull %Q0, %R0, %Q1, %Q2\n\t" \ | ||
173 | "cmn %Q0, %Q1\n\t" \ | ||
174 | "adcs %R0, %R0, %R1\n\t" \ | ||
175 | "adc %Q0, %3, #0" \ | ||
176 | : "=&r" (__res) \ | ||
177 | : "r" (__m), "r" (__n), "r" (__z) \ | ||
178 | : "cc" ); \ | ||
179 | } \ | ||
180 | if (!(__m & ((1ULL << 63) | (1ULL << 31)))) { \ | ||
181 | asm ( "umlal %R0, %Q0, %R1, %Q2\n\t" \ | ||
182 | "umlal %R0, %Q0, %Q1, %R2\n\t" \ | ||
183 | "mov %R0, #0\n\t" \ | ||
184 | "umlal %Q0, %R0, %R1, %R2" \ | ||
185 | : "+r" (__res) \ | ||
186 | : "r" (__m), "r" (__n) \ | ||
187 | : "cc" ); \ | ||
188 | } else { \ | ||
189 | asm ( "umlal %R0, %Q0, %R2, %Q3\n\t" \ | ||
190 | "umlal %R0, %1, %Q2, %R3\n\t" \ | ||
191 | "mov %R0, #0\n\t" \ | ||
192 | "adds %Q0, %1, %Q0\n\t" \ | ||
193 | "adc %R0, %R0, #0\n\t" \ | ||
194 | "umlal %Q0, %R0, %R2, %R3" \ | ||
195 | : "+r" (__res), "+r" (__z) \ | ||
196 | : "r" (__m), "r" (__n) \ | ||
197 | : "cc" ); \ | ||
198 | } \ | ||
199 | __res /= __p; \ | ||
200 | /* The reminder can be computed with 32-bit regs */ \ | ||
201 | /* only, and gcc is good at that. */ \ | ||
202 | { \ | ||
203 | unsigned int __res0 = __res; \ | ||
204 | unsigned int __b0 = __b; \ | ||
205 | __r -= __res0 * __b0; \ | ||
206 | } \ | ||
207 | /* BUG_ON(__r >= __b || __res * __b + __r != n); */ \ | ||
208 | n = __res; \ | ||
209 | } \ | ||
210 | __r; \ | ||
211 | }) | ||
212 | |||
213 | /* our own fls implementation to make sure constant propagation is fine */ | ||
214 | #define __div64_fls(bits) \ | ||
215 | ({ \ | ||
216 | unsigned int __left = (bits), __nr = 0; \ | ||
217 | if (__left & 0xffff0000) __nr += 16, __left >>= 16; \ | ||
218 | if (__left & 0x0000ff00) __nr += 8, __left >>= 8; \ | ||
219 | if (__left & 0x000000f0) __nr += 4, __left >>= 4; \ | ||
220 | if (__left & 0x0000000c) __nr += 2, __left >>= 2; \ | ||
221 | if (__left & 0x00000002) __nr += 1; \ | ||
222 | __nr; \ | ||
223 | }) | ||
224 | |||
225 | #endif | ||
226 | |||
227 | #endif | ||