]>
Commit | Line | Data |
---|---|---|
7857f134 | 1 | @ libgcc routines for ARM cpu. |
bd28bf5a | 2 | @ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) |
454e0249 | 3 | |
a4de48bc | 4 | /* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005 |
46049cff | 5 | Free Software Foundation, Inc. |
454e0249 DE |
6 | |
7 | This file is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU General Public License as published by the | |
9 | Free Software Foundation; either version 2, or (at your option) any | |
10 | later version. | |
11 | ||
12 | In addition to the permissions in the GNU General Public License, the | |
13 | Free Software Foundation gives you unlimited permission to link the | |
f7af368f JL |
14 | compiled version of this file into combinations with other programs, |
15 | and to distribute those combinations without any restriction coming | |
16 | from the use of this file. (The General Public License restrictions | |
17 | do apply in other respects; for example, they cover modification of | |
18 | the file, and distribution when not linked into a combine | |
19 | executable.) | |
454e0249 DE |
20 | |
21 | This file is distributed in the hope that it will be useful, but | |
22 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
24 | General Public License for more details. | |
25 | ||
26 | You should have received a copy of the GNU General Public License | |
27 | along with this program; see the file COPYING. If not, write to | |
39d14dda KC |
28 | the Free Software Foundation, 51 Franklin Street, Fifth Floor, |
29 | Boston, MA 02110-1301, USA. */ | |
6dcd26ea | 30 | /* ------------------------------------------------------------------------ */ |
888e552f NC |
31 | |
32 | /* We need to know what prefix to add to function names. */ | |
33 | ||
2a5307b1 NC |
34 | #ifndef __USER_LABEL_PREFIX__ |
35 | #error __USER_LABEL_PREFIX__ not defined | |
36 | #endif | |
37 | ||
a1e27b76 NC |
38 | /* ANSI concatenation macros. */ |
39 | ||
40 | #define CONCAT1(a, b) CONCAT2(a, b) | |
41 | #define CONCAT2(a, b) a ## b | |
42 | ||
43 | /* Use the right prefix for global labels. */ | |
44 | ||
45 | #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) | |
46 | ||
140fa895 | 47 | #ifdef __ELF__ |
d5b7b3ae | 48 | #ifdef __thumb__ |
6dcd26ea | 49 | #define __PLT__ /* Not supported in Thumb assembler (for now). */ |
d5b7b3ae | 50 | #else |
b355a481 | 51 | #define __PLT__ (PLT) |
d5b7b3ae | 52 | #endif |
b355a481 NC |
53 | #define TYPE(x) .type SYM(x),function |
54 | #define SIZE(x) .size SYM(x), . - SYM(x) | |
ce250a20 | 55 | #define LSYM(x) .x |
b355a481 NC |
56 | #else |
57 | #define __PLT__ | |
58 | #define TYPE(x) | |
59 | #define SIZE(x) | |
ce250a20 | 60 | #define LSYM(x) x |
b355a481 NC |
61 | #endif |
62 | ||
61f0ccff | 63 | /* Function end macros. Variants for interworking. */ |
888e552f | 64 | |
496b84c8 RE |
65 | @ This selects the minimum architecture level required. |
66 | #define __ARM_ARCH__ 3 | |
67 | ||
68 | #if defined(__ARM_ARCH_3M__) || defined(__ARM_ARCH_4__) \ | |
69 | || defined(__ARM_ARCH_4T__) | |
70 | /* We use __ARM_ARCH__ set to 4 here, but in reality it's any processor with | |
71 | long multiply instructions. That includes v3M. */ | |
72 | # undef __ARM_ARCH__ | |
73 | # define __ARM_ARCH__ 4 | |
74 | #endif | |
75 | ||
76 | #if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ | |
e0d4a859 PB |
77 | || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ |
78 | || defined(__ARM_ARCH_5TEJ__) | |
496b84c8 RE |
79 | # undef __ARM_ARCH__ |
80 | # define __ARM_ARCH__ 5 | |
81 | #endif | |
82 | ||
fa91adc6 PB |
83 | #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ |
84 | || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ | |
85 | || defined(__ARM_ARCH_6ZK__) | |
e0d4a859 PB |
86 | # undef __ARM_ARCH__ |
87 | # define __ARM_ARCH__ 6 | |
88 | #endif | |
89 | ||
496b84c8 RE |
90 | /* How to return from a function call depends on the architecture variant. */ |
91 | ||
61f0ccff | 92 | #if (__ARM_ARCH__ > 4) || defined(__ARM_ARCH_4T__) |
496b84c8 RE |
93 | |
94 | # define RET bx lr | |
95 | # define RETc(x) bx##x lr | |
96 | ||
4c5f9898 PB |
97 | /* Special precautions for interworking on armv4t. */ |
98 | # if (__ARM_ARCH__ == 4) | |
99 | ||
100 | /* Always use bx, not ldr pc. */ | |
101 | # if (defined(__thumb__) || defined(__THUMB_INTERWORK__)) | |
102 | # define __INTERWORKING__ | |
103 | # endif /* __THUMB__ || __THUMB_INTERWORK__ */ | |
104 | ||
105 | /* Include thumb stub before arm mode code. */ | |
106 | # if defined(__thumb__) && !defined(__THUMB_INTERWORK__) | |
107 | # define __INTERWORKING_STUBS__ | |
108 | # endif /* __thumb__ && !__THUMB_INTERWORK__ */ | |
109 | ||
110 | #endif /* __ARM_ARCH == 4 */ | |
496b84c8 RE |
111 | |
112 | #else | |
113 | ||
114 | # define RET mov pc, lr | |
115 | # define RETc(x) mov##x pc, lr | |
116 | ||
117 | #endif | |
118 | ||
d0f11b16 DJ |
119 | .macro cfi_pop advance, reg, cfa_offset |
120 | #ifdef __ELF__ | |
121 | .pushsection .debug_frame | |
122 | .byte 0x4 /* DW_CFA_advance_loc4 */ | |
123 | .4byte \advance | |
124 | .byte (0xc0 | \reg) /* DW_CFA_restore */ | |
125 | .byte 0xe /* DW_CFA_def_cfa_offset */ | |
126 | .uleb128 \cfa_offset | |
127 | .popsection | |
128 | #endif | |
129 | .endm | |
130 | .macro cfi_push advance, reg, offset, cfa_offset | |
131 | #ifdef __ELF__ | |
132 | .pushsection .debug_frame | |
133 | .byte 0x4 /* DW_CFA_advance_loc4 */ | |
134 | .4byte \advance | |
135 | .byte (0x80 | \reg) /* DW_CFA_offset */ | |
136 | .uleb128 (\offset / -4) | |
137 | .byte 0xe /* DW_CFA_def_cfa_offset */ | |
138 | .uleb128 \cfa_offset | |
139 | .popsection | |
140 | #endif | |
141 | .endm | |
142 | .macro cfi_start start_label, end_label | |
143 | #ifdef __ELF__ | |
144 | .pushsection .debug_frame | |
145 | LSYM(Lstart_frame): | |
146 | .4byte LSYM(Lend_cie) - LSYM(Lstart_cie) @ Length of CIE | |
147 | LSYM(Lstart_cie): | |
148 | .4byte 0xffffffff @ CIE Identifier Tag | |
149 | .byte 0x1 @ CIE Version | |
150 | .ascii "\0" @ CIE Augmentation | |
151 | .uleb128 0x1 @ CIE Code Alignment Factor | |
152 | .sleb128 -4 @ CIE Data Alignment Factor | |
153 | .byte 0xe @ CIE RA Column | |
154 | .byte 0xc @ DW_CFA_def_cfa | |
155 | .uleb128 0xd | |
156 | .uleb128 0x0 | |
157 | ||
158 | .align 2 | |
159 | LSYM(Lend_cie): | |
160 | .4byte LSYM(Lend_fde)-LSYM(Lstart_fde) @ FDE Length | |
161 | LSYM(Lstart_fde): | |
162 | .4byte LSYM(Lstart_frame) @ FDE CIE offset | |
163 | .4byte \start_label @ FDE initial location | |
164 | .4byte \end_label-\start_label @ FDE address range | |
165 | .popsection | |
166 | #endif | |
167 | .endm | |
168 | .macro cfi_end end_label | |
169 | #ifdef __ELF__ | |
170 | .pushsection .debug_frame | |
171 | .align 2 | |
172 | LSYM(Lend_fde): | |
173 | .popsection | |
174 | \end_label: | |
175 | #endif | |
176 | .endm | |
177 | ||
496b84c8 RE |
178 | /* Don't pass dirn, it's there just to get token pasting right. */ |
179 | ||
d0f11b16 | 180 | .macro RETLDM regs=, cond=, unwind=, dirn=ia |
61f0ccff | 181 | #if defined (__INTERWORKING__) |
496b84c8 | 182 | .ifc "\regs","" |
d0f11b16 | 183 | ldr\cond lr, [sp], #8 |
496b84c8 RE |
184 | .else |
185 | ldm\cond\dirn sp!, {\regs, lr} | |
d0f11b16 DJ |
186 | .endif |
187 | .ifnc "\unwind", "" | |
188 | /* Mark LR as restored. */ | |
189 | 97: cfi_pop 97b - \unwind, 0xe, 0x0 | |
496b84c8 RE |
190 | .endif |
191 | bx\cond lr | |
192 | #else | |
193 | .ifc "\regs","" | |
d0f11b16 | 194 | ldr\cond pc, [sp], #8 |
496b84c8 RE |
195 | .else |
196 | ldm\cond\dirn sp!, {\regs, pc} | |
197 | .endif | |
198 | #endif | |
199 | .endm | |
200 | ||
201 | ||
d0f11b16 DJ |
202 | .macro ARM_LDIV0 name |
203 | str lr, [sp, #-8]! | |
204 | 98: cfi_push 98b - __\name, 0xe, -0x8, 0x8 | |
6dcd26ea RE |
205 | bl SYM (__div0) __PLT__ |
206 | mov r0, #0 @ About as wrong as it could be. | |
d0f11b16 | 207 | RETLDM unwind=98b |
6dcd26ea | 208 | .endm |
496b84c8 RE |
209 | |
210 | ||
d0f11b16 DJ |
211 | .macro THUMB_LDIV0 name |
212 | push { r1, lr } | |
213 | 98: cfi_push 98b - __\name, 0xe, -0x4, 0x8 | |
6dcd26ea RE |
214 | bl SYM (__div0) |
215 | mov r0, #0 @ About as wrong as it could be. | |
496b84c8 | 216 | #if defined (__INTERWORKING__) |
d0f11b16 DJ |
217 | pop { r1, r2 } |
218 | bx r2 | |
496b84c8 | 219 | #else |
d0f11b16 | 220 | pop { r1, pc } |
6dcd26ea | 221 | #endif |
496b84c8 | 222 | .endm |
6dcd26ea | 223 | |
888e552f | 224 | .macro FUNC_END name |
496b84c8 RE |
225 | SIZE (__\name) |
226 | .endm | |
227 | ||
228 | .macro DIV_FUNC_END name | |
d0f11b16 | 229 | cfi_start __\name, LSYM(Lend_div0) |
ce250a20 | 230 | LSYM(Ldiv0): |
888e552f | 231 | #ifdef __thumb__ |
d0f11b16 | 232 | THUMB_LDIV0 \name |
888e552f | 233 | #else |
d0f11b16 | 234 | ARM_LDIV0 \name |
888e552f | 235 | #endif |
d0f11b16 | 236 | cfi_end LSYM(Lend_div0) |
496b84c8 | 237 | FUNC_END \name |
888e552f NC |
238 | .endm |
239 | ||
240 | .macro THUMB_FUNC_START name | |
241 | .globl SYM (\name) | |
242 | TYPE (\name) | |
243 | .thumb_func | |
244 | SYM (\name): | |
245 | .endm | |
246 | ||
247 | /* Function start macros. Variants for ARM and Thumb. */ | |
248 | ||
d5b7b3ae RE |
249 | #ifdef __thumb__ |
250 | #define THUMB_FUNC .thumb_func | |
251 | #define THUMB_CODE .force_thumb | |
252 | #else | |
253 | #define THUMB_FUNC | |
254 | #define THUMB_CODE | |
255 | #endif | |
256 | ||
d5b7b3ae RE |
257 | .macro FUNC_START name |
258 | .text | |
259 | .globl SYM (__\name) | |
260 | TYPE (__\name) | |
261 | .align 0 | |
262 | THUMB_CODE | |
263 | THUMB_FUNC | |
264 | SYM (__\name): | |
265 | .endm | |
496b84c8 RE |
266 | |
267 | /* Special function that will always be coded in ARM assembly, even if | |
268 | in Thumb-only compilation. */ | |
269 | ||
4c5f9898 | 270 | #if defined(__INTERWORKING_STUBS__) |
496b84c8 RE |
271 | .macro ARM_FUNC_START name |
272 | FUNC_START \name | |
273 | bx pc | |
274 | nop | |
275 | .arm | |
db151e9d PB |
276 | /* A hook to tell gdb that we've switched to ARM mode. Also used to call |
277 | directly from other local arm routines. */ | |
278 | _L__\name: | |
496b84c8 | 279 | .endm |
46049cff | 280 | #define EQUIV .thumb_set |
db151e9d PB |
281 | /* Branch directly to a function declared with ARM_FUNC_START. |
282 | Must be called in arm mode. */ | |
b3f8d95d MM |
283 | .macro ARM_CALL name |
284 | bl _L__\name | |
285 | .endm | |
496b84c8 RE |
286 | #else |
287 | .macro ARM_FUNC_START name | |
46049cff RE |
288 | .text |
289 | .globl SYM (__\name) | |
290 | TYPE (__\name) | |
291 | .align 0 | |
292 | .arm | |
293 | SYM (__\name): | |
496b84c8 | 294 | .endm |
46049cff | 295 | #define EQUIV .set |
b3f8d95d MM |
296 | .macro ARM_CALL name |
297 | bl __\name | |
298 | .endm | |
496b84c8 RE |
299 | #endif |
300 | ||
2155b886 RE |
301 | .macro FUNC_ALIAS new old |
302 | .globl SYM (__\new) | |
4c5f9898 PB |
303 | #if defined (__thumb__) |
304 | .thumb_set SYM (__\new), SYM (__\old) | |
305 | #else | |
306 | .set SYM (__\new), SYM (__\old) | |
307 | #endif | |
2155b886 RE |
308 | .endm |
309 | ||
46049cff RE |
310 | .macro ARM_FUNC_ALIAS new old |
311 | .globl SYM (__\new) | |
312 | EQUIV SYM (__\new), SYM (__\old) | |
4c5f9898 | 313 | #if defined(__INTERWORKING_STUBS__) |
db151e9d PB |
314 | .set SYM (_L__\new), SYM (_L__\old) |
315 | #endif | |
46049cff RE |
316 | .endm |
317 | ||
6a436e5e | 318 | #ifdef __thumb__ |
888e552f | 319 | /* Register aliases. */ |
454e0249 | 320 | |
888e552f | 321 | work .req r4 @ XXXX is this safe ? |
bd28bf5a RE |
322 | dividend .req r0 |
323 | divisor .req r1 | |
888e552f | 324 | overdone .req r2 |
bd28bf5a RE |
325 | result .req r2 |
326 | curbit .req r3 | |
6a436e5e | 327 | #endif |
5a9335ef | 328 | #if 0 |
bd28bf5a RE |
329 | ip .req r12 |
330 | sp .req r13 | |
331 | lr .req r14 | |
332 | pc .req r15 | |
5a9335ef | 333 | #endif |
6a436e5e | 334 | |
888e552f | 335 | /* ------------------------------------------------------------------------ */ |
9a9f7594 | 336 | /* Bodies of the division and modulo routines. */ |
888e552f | 337 | /* ------------------------------------------------------------------------ */ |
6a436e5e NP |
338 | .macro ARM_DIV_BODY dividend, divisor, result, curbit |
339 | ||
9b66ebb1 PB |
340 | #if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__) |
341 | ||
342 | clz \curbit, \dividend | |
343 | clz \result, \divisor | |
344 | sub \curbit, \result, \curbit | |
345 | rsbs \curbit, \curbit, #31 | |
346 | addne \curbit, \curbit, \curbit, lsl #1 | |
347 | mov \result, #0 | |
348 | addne pc, pc, \curbit, lsl #2 | |
349 | nop | |
350 | .set shift, 32 | |
351 | .rept 32 | |
352 | .set shift, shift - 1 | |
353 | cmp \dividend, \divisor, lsl #shift | |
354 | adc \result, \result, \result | |
355 | subcs \dividend, \dividend, \divisor, lsl #shift | |
356 | .endr | |
357 | ||
358 | #else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ | |
6a436e5e NP |
359 | #if __ARM_ARCH__ >= 5 |
360 | ||
361 | clz \curbit, \divisor | |
362 | clz \result, \dividend | |
363 | sub \result, \curbit, \result | |
364 | mov \curbit, #1 | |
365 | mov \divisor, \divisor, lsl \result | |
366 | mov \curbit, \curbit, lsl \result | |
367 | mov \result, #0 | |
368 | ||
9b66ebb1 | 369 | #else /* __ARM_ARCH__ < 5 */ |
6a436e5e NP |
370 | |
371 | @ Initially shift the divisor left 3 bits if possible, | |
372 | @ set curbit accordingly. This allows for curbit to be located | |
373 | @ at the left end of each 4 bit nibbles in the division loop | |
374 | @ to save one loop in most cases. | |
375 | tst \divisor, #0xe0000000 | |
376 | moveq \divisor, \divisor, lsl #3 | |
377 | moveq \curbit, #8 | |
378 | movne \curbit, #1 | |
379 | ||
bd28bf5a RE |
380 | @ Unless the divisor is very big, shift it up in multiples of |
381 | @ four bits, since this is the amount of unwinding in the main | |
382 | @ division loop. Continue shifting until the divisor is | |
383 | @ larger than the dividend. | |
6a436e5e NP |
384 | 1: cmp \divisor, #0x10000000 |
385 | cmplo \divisor, \dividend | |
386 | movlo \divisor, \divisor, lsl #4 | |
387 | movlo \curbit, \curbit, lsl #4 | |
388 | blo 1b | |
bd28bf5a | 389 | |
bd28bf5a RE |
390 | @ For very big divisors, we must shift it a bit at a time, or |
391 | @ we will be in danger of overflowing. | |
6a436e5e NP |
392 | 1: cmp \divisor, #0x80000000 |
393 | cmplo \divisor, \dividend | |
394 | movlo \divisor, \divisor, lsl #1 | |
395 | movlo \curbit, \curbit, lsl #1 | |
396 | blo 1b | |
bd28bf5a | 397 | |
6a436e5e NP |
398 | mov \result, #0 |
399 | ||
9b66ebb1 | 400 | #endif /* __ARM_ARCH__ < 5 */ |
6a436e5e NP |
401 | |
402 | @ Division loop | |
403 | 1: cmp \dividend, \divisor | |
404 | subhs \dividend, \dividend, \divisor | |
405 | orrhs \result, \result, \curbit | |
406 | cmp \dividend, \divisor, lsr #1 | |
407 | subhs \dividend, \dividend, \divisor, lsr #1 | |
408 | orrhs \result, \result, \curbit, lsr #1 | |
409 | cmp \dividend, \divisor, lsr #2 | |
410 | subhs \dividend, \dividend, \divisor, lsr #2 | |
411 | orrhs \result, \result, \curbit, lsr #2 | |
412 | cmp \dividend, \divisor, lsr #3 | |
413 | subhs \dividend, \dividend, \divisor, lsr #3 | |
414 | orrhs \result, \result, \curbit, lsr #3 | |
415 | cmp \dividend, #0 @ Early termination? | |
416 | movnes \curbit, \curbit, lsr #4 @ No, any more bits to do? | |
417 | movne \divisor, \divisor, lsr #4 | |
418 | bne 1b | |
419 | ||
9b66ebb1 PB |
420 | #endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ |
421 | ||
6a436e5e NP |
422 | .endm |
423 | /* ------------------------------------------------------------------------ */ | |
424 | .macro ARM_DIV2_ORDER divisor, order | |
425 | ||
426 | #if __ARM_ARCH__ >= 5 | |
427 | ||
428 | clz \order, \divisor | |
429 | rsb \order, \order, #31 | |
430 | ||
431 | #else | |
432 | ||
433 | cmp \divisor, #(1 << 16) | |
434 | movhs \divisor, \divisor, lsr #16 | |
435 | movhs \order, #16 | |
436 | movlo \order, #0 | |
437 | ||
438 | cmp \divisor, #(1 << 8) | |
439 | movhs \divisor, \divisor, lsr #8 | |
440 | addhs \order, \order, #8 | |
441 | ||
442 | cmp \divisor, #(1 << 4) | |
443 | movhs \divisor, \divisor, lsr #4 | |
444 | addhs \order, \order, #4 | |
445 | ||
446 | cmp \divisor, #(1 << 2) | |
447 | addhi \order, \order, #3 | |
448 | addls \order, \order, \divisor, lsr #1 | |
449 | ||
450 | #endif | |
451 | ||
452 | .endm | |
453 | /* ------------------------------------------------------------------------ */ | |
454 | .macro ARM_MOD_BODY dividend, divisor, order, spare | |
455 | ||
9b66ebb1 PB |
456 | #if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__) |
457 | ||
458 | clz \order, \divisor | |
459 | clz \spare, \dividend | |
460 | sub \order, \order, \spare | |
461 | rsbs \order, \order, #31 | |
462 | addne pc, pc, \order, lsl #3 | |
463 | nop | |
464 | .set shift, 32 | |
465 | .rept 32 | |
466 | .set shift, shift - 1 | |
467 | cmp \dividend, \divisor, lsl #shift | |
468 | subcs \dividend, \dividend, \divisor, lsl #shift | |
469 | .endr | |
470 | ||
471 | #else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ | |
6a436e5e NP |
472 | #if __ARM_ARCH__ >= 5 |
473 | ||
474 | clz \order, \divisor | |
475 | clz \spare, \dividend | |
476 | sub \order, \order, \spare | |
477 | mov \divisor, \divisor, lsl \order | |
888e552f | 478 | |
9b66ebb1 | 479 | #else /* __ARM_ARCH__ < 5 */ |
454e0249 | 480 | |
6a436e5e | 481 | mov \order, #0 |
454e0249 | 482 | |
6a436e5e NP |
483 | @ Unless the divisor is very big, shift it up in multiples of |
484 | @ four bits, since this is the amount of unwinding in the main | |
485 | @ division loop. Continue shifting until the divisor is | |
486 | @ larger than the dividend. | |
487 | 1: cmp \divisor, #0x10000000 | |
488 | cmplo \divisor, \dividend | |
489 | movlo \divisor, \divisor, lsl #4 | |
490 | addlo \order, \order, #4 | |
491 | blo 1b | |
b355a481 | 492 | |
6a436e5e NP |
493 | @ For very big divisors, we must shift it a bit at a time, or |
494 | @ we will be in danger of overflowing. | |
495 | 1: cmp \divisor, #0x80000000 | |
496 | cmplo \divisor, \dividend | |
497 | movlo \divisor, \divisor, lsl #1 | |
498 | addlo \order, \order, #1 | |
499 | blo 1b | |
500 | ||
9b66ebb1 | 501 | #endif /* __ARM_ARCH__ < 5 */ |
6a436e5e NP |
502 | |
503 | @ Perform all needed substractions to keep only the reminder. | |
504 | @ Do comparisons in batch of 4 first. | |
505 | subs \order, \order, #3 @ yes, 3 is intended here | |
506 | blt 2f | |
507 | ||
508 | 1: cmp \dividend, \divisor | |
509 | subhs \dividend, \dividend, \divisor | |
510 | cmp \dividend, \divisor, lsr #1 | |
511 | subhs \dividend, \dividend, \divisor, lsr #1 | |
512 | cmp \dividend, \divisor, lsr #2 | |
513 | subhs \dividend, \dividend, \divisor, lsr #2 | |
514 | cmp \dividend, \divisor, lsr #3 | |
515 | subhs \dividend, \dividend, \divisor, lsr #3 | |
516 | cmp \dividend, #1 | |
517 | mov \divisor, \divisor, lsr #4 | |
518 | subges \order, \order, #4 | |
519 | bge 1b | |
520 | ||
521 | tst \order, #3 | |
522 | teqne \dividend, #0 | |
523 | beq 5f | |
524 | ||
525 | @ Either 1, 2 or 3 comparison/substractions are left. | |
526 | 2: cmn \order, #2 | |
527 | blt 4f | |
528 | beq 3f | |
529 | cmp \dividend, \divisor | |
530 | subhs \dividend, \dividend, \divisor | |
531 | mov \divisor, \divisor, lsr #1 | |
532 | 3: cmp \dividend, \divisor | |
533 | subhs \dividend, \dividend, \divisor | |
534 | mov \divisor, \divisor, lsr #1 | |
535 | 4: cmp \dividend, \divisor | |
536 | subhs \dividend, \dividend, \divisor | |
537 | 5: | |
9b66ebb1 PB |
538 | |
539 | #endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ | |
540 | ||
888e552f | 541 | .endm |
6dcd26ea | 542 | /* ------------------------------------------------------------------------ */ |
888e552f NC |
543 | .macro THUMB_DIV_MOD_BODY modulo |
544 | @ Load the constant 0x10000000 into our work register. | |
d5b7b3ae RE |
545 | mov work, #1 |
546 | lsl work, #28 | |
ce250a20 | 547 | LSYM(Loop1): |
d5b7b3ae RE |
548 | @ Unless the divisor is very big, shift it up in multiples of |
549 | @ four bits, since this is the amount of unwinding in the main | |
550 | @ division loop. Continue shifting until the divisor is | |
551 | @ larger than the dividend. | |
552 | cmp divisor, work | |
ce250a20 | 553 | bhs LSYM(Lbignum) |
d5b7b3ae | 554 | cmp divisor, dividend |
ce250a20 | 555 | bhs LSYM(Lbignum) |
d5b7b3ae | 556 | lsl divisor, #4 |
888e552f | 557 | lsl curbit, #4 |
ce250a20 RE |
558 | b LSYM(Loop1) |
559 | LSYM(Lbignum): | |
d5b7b3ae RE |
560 | @ Set work to 0x80000000 |
561 | lsl work, #3 | |
ce250a20 | 562 | LSYM(Loop2): |
d5b7b3ae RE |
563 | @ For very big divisors, we must shift it a bit at a time, or |
564 | @ we will be in danger of overflowing. | |
565 | cmp divisor, work | |
ce250a20 | 566 | bhs LSYM(Loop3) |
d5b7b3ae | 567 | cmp divisor, dividend |
ce250a20 | 568 | bhs LSYM(Loop3) |
d5b7b3ae | 569 | lsl divisor, #1 |
888e552f | 570 | lsl curbit, #1 |
ce250a20 RE |
571 | b LSYM(Loop2) |
572 | LSYM(Loop3): | |
888e552f NC |
573 | @ Test for possible subtractions ... |
574 | .if \modulo | |
575 | @ ... On the final pass, this may subtract too much from the dividend, | |
576 | @ so keep track of which subtractions are done, we can fix them up | |
577 | @ afterwards. | |
d5b7b3ae RE |
578 | mov overdone, #0 |
579 | cmp dividend, divisor | |
ce250a20 | 580 | blo LSYM(Lover1) |
d5b7b3ae | 581 | sub dividend, dividend, divisor |
ce250a20 | 582 | LSYM(Lover1): |
d5b7b3ae RE |
583 | lsr work, divisor, #1 |
584 | cmp dividend, work | |
ce250a20 | 585 | blo LSYM(Lover2) |
d5b7b3ae RE |
586 | sub dividend, dividend, work |
587 | mov ip, curbit | |
588 | mov work, #1 | |
589 | ror curbit, work | |
590 | orr overdone, curbit | |
591 | mov curbit, ip | |
ce250a20 | 592 | LSYM(Lover2): |
d5b7b3ae RE |
593 | lsr work, divisor, #2 |
594 | cmp dividend, work | |
ce250a20 | 595 | blo LSYM(Lover3) |
d5b7b3ae RE |
596 | sub dividend, dividend, work |
597 | mov ip, curbit | |
598 | mov work, #2 | |
599 | ror curbit, work | |
600 | orr overdone, curbit | |
601 | mov curbit, ip | |
ce250a20 | 602 | LSYM(Lover3): |
d5b7b3ae RE |
603 | lsr work, divisor, #3 |
604 | cmp dividend, work | |
ce250a20 | 605 | blo LSYM(Lover4) |
d5b7b3ae RE |
606 | sub dividend, dividend, work |
607 | mov ip, curbit | |
608 | mov work, #3 | |
609 | ror curbit, work | |
610 | orr overdone, curbit | |
611 | mov curbit, ip | |
ce250a20 | 612 | LSYM(Lover4): |
d5b7b3ae | 613 | mov ip, curbit |
888e552f NC |
614 | .else |
615 | @ ... and note which bits are done in the result. On the final pass, | |
616 | @ this may subtract too much from the dividend, but the result will be ok, | |
617 | @ since the "bit" will have been shifted out at the bottom. | |
618 | cmp dividend, divisor | |
ce250a20 | 619 | blo LSYM(Lover1) |
888e552f NC |
620 | sub dividend, dividend, divisor |
621 | orr result, result, curbit | |
ba2f4247 | 622 | LSYM(Lover1): |
888e552f NC |
623 | lsr work, divisor, #1 |
624 | cmp dividend, work | |
ce250a20 | 625 | blo LSYM(Lover2) |
888e552f NC |
626 | sub dividend, dividend, work |
627 | lsr work, curbit, #1 | |
628 | orr result, work | |
ce250a20 | 629 | LSYM(Lover2): |
888e552f NC |
630 | lsr work, divisor, #2 |
631 | cmp dividend, work | |
ce250a20 | 632 | blo LSYM(Lover3) |
888e552f NC |
633 | sub dividend, dividend, work |
634 | lsr work, curbit, #2 | |
635 | orr result, work | |
ce250a20 | 636 | LSYM(Lover3): |
888e552f NC |
637 | lsr work, divisor, #3 |
638 | cmp dividend, work | |
ce250a20 | 639 | blo LSYM(Lover4) |
888e552f NC |
640 | sub dividend, dividend, work |
641 | lsr work, curbit, #3 | |
642 | orr result, work | |
ce250a20 | 643 | LSYM(Lover4): |
888e552f NC |
644 | .endif |
645 | ||
d5b7b3ae | 646 | cmp dividend, #0 @ Early termination? |
ce250a20 | 647 | beq LSYM(Lover5) |
888e552f | 648 | lsr curbit, #4 @ No, any more bits to do? |
ce250a20 | 649 | beq LSYM(Lover5) |
d5b7b3ae | 650 | lsr divisor, #4 |
ce250a20 RE |
651 | b LSYM(Loop3) |
652 | LSYM(Lover5): | |
888e552f | 653 | .if \modulo |
d5b7b3ae RE |
654 | @ Any subtractions that we should not have done will be recorded in |
655 | @ the top three bits of "overdone". Exactly which were not needed | |
656 | @ are governed by the position of the bit, stored in ip. | |
d5b7b3ae | 657 | mov work, #0xe |
888e552f | 658 | lsl work, #28 |
d5b7b3ae | 659 | and overdone, work |
ce250a20 | 660 | beq LSYM(Lgot_result) |
7405dc37 NC |
661 | |
662 | @ If we terminated early, because dividend became zero, then the | |
663 | @ bit in ip will not be in the bottom nibble, and we should not | |
664 | @ perform the additions below. We must test for this though | |
665 | @ (rather relying upon the TSTs to prevent the additions) since | |
666 | @ the bit in ip could be in the top two bits which might then match | |
667 | @ with one of the smaller RORs. | |
668 | mov curbit, ip | |
669 | mov work, #0x7 | |
670 | tst curbit, work | |
ce250a20 | 671 | beq LSYM(Lgot_result) |
7405dc37 | 672 | |
d5b7b3ae RE |
673 | mov curbit, ip |
674 | mov work, #3 | |
675 | ror curbit, work | |
676 | tst overdone, curbit | |
ce250a20 | 677 | beq LSYM(Lover6) |
d5b7b3ae | 678 | lsr work, divisor, #3 |
888e552f | 679 | add dividend, work |
ce250a20 | 680 | LSYM(Lover6): |
d5b7b3ae RE |
681 | mov curbit, ip |
682 | mov work, #2 | |
683 | ror curbit, work | |
684 | tst overdone, curbit | |
ce250a20 | 685 | beq LSYM(Lover7) |
d5b7b3ae | 686 | lsr work, divisor, #2 |
888e552f | 687 | add dividend, work |
ce250a20 | 688 | LSYM(Lover7): |
d5b7b3ae RE |
689 | mov curbit, ip |
690 | mov work, #1 | |
691 | ror curbit, work | |
692 | tst overdone, curbit | |
ce250a20 | 693 | beq LSYM(Lgot_result) |
d5b7b3ae | 694 | lsr work, divisor, #1 |
888e552f NC |
695 | add dividend, work |
696 | .endif | |
ce250a20 | 697 | LSYM(Lgot_result): |
888e552f NC |
698 | .endm |
699 | /* ------------------------------------------------------------------------ */ | |
700 | /* Start of the Real Functions */ | |
701 | /* ------------------------------------------------------------------------ */ | |
702 | #ifdef L_udivsi3 | |
703 | ||
704 | FUNC_START udivsi3 | |
705 | ||
706 | #ifdef __thumb__ | |
707 | ||
708 | cmp divisor, #0 | |
ce250a20 | 709 | beq LSYM(Ldiv0) |
888e552f NC |
710 | mov curbit, #1 |
711 | mov result, #0 | |
712 | ||
713 | push { work } | |
714 | cmp dividend, divisor | |
ce250a20 | 715 | blo LSYM(Lgot_result) |
888e552f NC |
716 | |
717 | THUMB_DIV_MOD_BODY 0 | |
718 | ||
719 | mov r0, result | |
d5b7b3ae | 720 | pop { work } |
ef42b1dd | 721 | RET |
888e552f NC |
722 | |
723 | #else /* ARM version. */ | |
6a436e5e NP |
724 | |
725 | subs r2, r1, #1 | |
726 | RETc(eq) | |
727 | bcc LSYM(Ldiv0) | |
728 | cmp r0, r1 | |
729 | bls 11f | |
730 | tst r1, r2 | |
731 | beq 12f | |
d5b7b3ae | 732 | |
6a436e5e | 733 | ARM_DIV_BODY r0, r1, r2, r3 |
888e552f | 734 | |
6a436e5e | 735 | mov r0, r2 |
888e552f | 736 | RET |
bd28bf5a | 737 | |
6a436e5e NP |
738 | 11: moveq r0, #1 |
739 | movne r0, #0 | |
740 | RET | |
741 | ||
742 | 12: ARM_DIV2_ORDER r1, r2 | |
743 | ||
744 | mov r0, r0, lsr r2 | |
745 | RET | |
746 | ||
888e552f | 747 | #endif /* ARM version */ |
bd28bf5a | 748 | |
496b84c8 | 749 | DIV_FUNC_END udivsi3 |
888e552f | 750 | |
db151e9d PB |
751 | FUNC_START aeabi_uidivmod |
752 | #ifdef __thumb__ | |
753 | push {r0, r1, lr} | |
754 | bl SYM(__udivsi3) | |
755 | POP {r1, r2, r3} | |
756 | mul r2, r0 | |
757 | sub r1, r1, r2 | |
758 | bx r3 | |
759 | #else | |
b3f8d95d | 760 | stmfd sp!, { r0, r1, lr } |
db151e9d | 761 | bl SYM(__udivsi3) |
b3f8d95d MM |
762 | ldmfd sp!, { r1, r2, lr } |
763 | mul r3, r2, r0 | |
764 | sub r1, r1, r3 | |
765 | RET | |
db151e9d | 766 | #endif |
b3f8d95d MM |
767 | FUNC_END aeabi_uidivmod |
768 | ||
888e552f NC |
769 | #endif /* L_udivsi3 */ |
770 | /* ------------------------------------------------------------------------ */ | |
771 | #ifdef L_umodsi3 | |
772 | ||
773 | FUNC_START umodsi3 | |
774 | ||
775 | #ifdef __thumb__ | |
776 | ||
777 | cmp divisor, #0 | |
ce250a20 | 778 | beq LSYM(Ldiv0) |
888e552f | 779 | mov curbit, #1 |
bd28bf5a | 780 | cmp dividend, divisor |
ce250a20 | 781 | bhs LSYM(Lover10) |
888e552f | 782 | RET |
bd28bf5a | 783 | |
ce250a20 | 784 | LSYM(Lover10): |
888e552f NC |
785 | push { work } |
786 | ||
787 | THUMB_DIV_MOD_BODY 1 | |
788 | ||
789 | pop { work } | |
790 | RET | |
791 | ||
792 | #else /* ARM version. */ | |
793 | ||
6a436e5e NP |
794 | subs r2, r1, #1 @ compare divisor with 1 |
795 | bcc LSYM(Ldiv0) | |
796 | cmpne r0, r1 @ compare dividend with divisor | |
797 | moveq r0, #0 | |
798 | tsthi r1, r2 @ see if divisor is power of 2 | |
799 | andeq r0, r0, r2 | |
800 | RETc(ls) | |
801 | ||
802 | ARM_MOD_BODY r0, r1, r2, r3 | |
888e552f | 803 | |
d5b7b3ae | 804 | RET |
454e0249 | 805 | |
7405dc37 | 806 | #endif /* ARM version. */ |
d5b7b3ae | 807 | |
496b84c8 | 808 | DIV_FUNC_END umodsi3 |
b355a481 | 809 | |
bd28bf5a | 810 | #endif /* L_umodsi3 */ |
6dcd26ea | 811 | /* ------------------------------------------------------------------------ */ |
bd28bf5a | 812 | #ifdef L_divsi3 |
454e0249 | 813 | |
6dcd26ea | 814 | FUNC_START divsi3 |
d5b7b3ae RE |
815 | |
816 | #ifdef __thumb__ | |
817 | cmp divisor, #0 | |
ce250a20 | 818 | beq LSYM(Ldiv0) |
b355a481 | 819 | |
d5b7b3ae RE |
820 | push { work } |
821 | mov work, dividend | |
822 | eor work, divisor @ Save the sign of the result. | |
823 | mov ip, work | |
824 | mov curbit, #1 | |
825 | mov result, #0 | |
826 | cmp divisor, #0 | |
ce250a20 | 827 | bpl LSYM(Lover10) |
d5b7b3ae | 828 | neg divisor, divisor @ Loops below use unsigned. |
ce250a20 | 829 | LSYM(Lover10): |
d5b7b3ae | 830 | cmp dividend, #0 |
ce250a20 | 831 | bpl LSYM(Lover11) |
d5b7b3ae | 832 | neg dividend, dividend |
ce250a20 | 833 | LSYM(Lover11): |
d5b7b3ae | 834 | cmp dividend, divisor |
ce250a20 | 835 | blo LSYM(Lgot_result) |
d5b7b3ae | 836 | |
888e552f | 837 | THUMB_DIV_MOD_BODY 0 |
d5b7b3ae | 838 | |
d5b7b3ae RE |
839 | mov r0, result |
840 | mov work, ip | |
841 | cmp work, #0 | |
ce250a20 | 842 | bpl LSYM(Lover12) |
d5b7b3ae | 843 | neg r0, r0 |
ce250a20 | 844 | LSYM(Lover12): |
d5b7b3ae | 845 | pop { work } |
888e552f | 846 | RET |
454e0249 | 847 | |
6dcd26ea | 848 | #else /* ARM version. */ |
d5b7b3ae | 849 | |
6a436e5e NP |
850 | cmp r1, #0 |
851 | eor ip, r0, r1 @ save the sign of the result. | |
ce250a20 | 852 | beq LSYM(Ldiv0) |
6a436e5e NP |
853 | rsbmi r1, r1, #0 @ loops below use unsigned. |
854 | subs r2, r1, #1 @ division by 1 or -1 ? | |
855 | beq 10f | |
856 | movs r3, r0 | |
857 | rsbmi r3, r0, #0 @ positive dividend value | |
858 | cmp r3, r1 | |
859 | bls 11f | |
860 | tst r1, r2 @ divisor is power of 2 ? | |
861 | beq 12f | |
862 | ||
863 | ARM_DIV_BODY r3, r1, r0, r2 | |
888e552f | 864 | |
bd28bf5a | 865 | cmp ip, #0 |
02689e18 | 866 | rsbmi r0, r0, #0 |
d5b7b3ae | 867 | RET |
454e0249 | 868 | |
6a436e5e NP |
869 | 10: teq ip, r0 @ same sign ? |
870 | rsbmi r0, r0, #0 | |
871 | RET | |
872 | ||
873 | 11: movlo r0, #0 | |
874 | moveq r0, ip, asr #31 | |
875 | orreq r0, r0, #1 | |
876 | RET | |
877 | ||
878 | 12: ARM_DIV2_ORDER r1, r2 | |
879 | ||
880 | cmp ip, #0 | |
881 | mov r0, r3, lsr r2 | |
882 | rsbmi r0, r0, #0 | |
883 | RET | |
884 | ||
6dcd26ea | 885 | #endif /* ARM version */ |
d5b7b3ae | 886 | |
496b84c8 | 887 | DIV_FUNC_END divsi3 |
b355a481 | 888 | |
db151e9d PB |
889 | FUNC_START aeabi_idivmod |
890 | #ifdef __thumb__ | |
891 | push {r0, r1, lr} | |
892 | bl SYM(__divsi3) | |
893 | POP {r1, r2, r3} | |
894 | mul r2, r0 | |
895 | sub r1, r1, r2 | |
896 | bx r3 | |
897 | #else | |
b3f8d95d | 898 | stmfd sp!, { r0, r1, lr } |
db151e9d | 899 | bl SYM(__divsi3) |
b3f8d95d MM |
900 | ldmfd sp!, { r1, r2, lr } |
901 | mul r3, r2, r0 | |
902 | sub r1, r1, r3 | |
903 | RET | |
db151e9d | 904 | #endif |
b3f8d95d MM |
905 | FUNC_END aeabi_idivmod |
906 | ||
bd28bf5a | 907 | #endif /* L_divsi3 */ |
6dcd26ea | 908 | /* ------------------------------------------------------------------------ */ |
454e0249 DE |
909 | #ifdef L_modsi3 |
910 | ||
6dcd26ea | 911 | FUNC_START modsi3 |
d5b7b3ae RE |
912 | |
913 | #ifdef __thumb__ | |
454e0249 | 914 | |
d5b7b3ae RE |
915 | mov curbit, #1 |
916 | cmp divisor, #0 | |
ce250a20 RE |
917 | beq LSYM(Ldiv0) |
918 | bpl LSYM(Lover10) | |
d5b7b3ae | 919 | neg divisor, divisor @ Loops below use unsigned. |
ce250a20 | 920 | LSYM(Lover10): |
d5b7b3ae RE |
921 | push { work } |
922 | @ Need to save the sign of the dividend, unfortunately, we need | |
888e552f | 923 | @ work later on. Must do this after saving the original value of |
d5b7b3ae RE |
924 | @ the work register, because we will pop this value off first. |
925 | push { dividend } | |
926 | cmp dividend, #0 | |
ce250a20 | 927 | bpl LSYM(Lover11) |
d5b7b3ae | 928 | neg dividend, dividend |
ce250a20 | 929 | LSYM(Lover11): |
d5b7b3ae | 930 | cmp dividend, divisor |
ce250a20 | 931 | blo LSYM(Lgot_result) |
d5b7b3ae | 932 | |
888e552f NC |
933 | THUMB_DIV_MOD_BODY 1 |
934 | ||
d5b7b3ae RE |
935 | pop { work } |
936 | cmp work, #0 | |
ce250a20 | 937 | bpl LSYM(Lover12) |
d5b7b3ae | 938 | neg dividend, dividend |
ce250a20 | 939 | LSYM(Lover12): |
d5b7b3ae RE |
940 | pop { work } |
941 | RET | |
7405dc37 | 942 | |
6dcd26ea | 943 | #else /* ARM version. */ |
d5b7b3ae | 944 | |
6a436e5e | 945 | cmp r1, #0 |
ce250a20 | 946 | beq LSYM(Ldiv0) |
6a436e5e NP |
947 | rsbmi r1, r1, #0 @ loops below use unsigned. |
948 | movs ip, r0 @ preserve sign of dividend | |
949 | rsbmi r0, r0, #0 @ if negative make positive | |
950 | subs r2, r1, #1 @ compare divisor with 1 | |
951 | cmpne r0, r1 @ compare dividend with divisor | |
952 | moveq r0, #0 | |
953 | tsthi r1, r2 @ see if divisor is power of 2 | |
954 | andeq r0, r0, r2 | |
955 | bls 10f | |
956 | ||
957 | ARM_MOD_BODY r0, r1, r2, r3 | |
958 | ||
959 | 10: cmp ip, #0 | |
960 | rsbmi r0, r0, #0 | |
d5b7b3ae | 961 | RET |
7405dc37 | 962 | |
6dcd26ea RE |
963 | #endif /* ARM version */ |
964 | ||
496b84c8 | 965 | DIV_FUNC_END modsi3 |
b355a481 | 966 | |
454e0249 | 967 | #endif /* L_modsi3 */ |
6dcd26ea | 968 | /* ------------------------------------------------------------------------ */ |
2ecc7cad | 969 | #ifdef L_dvmd_tls |
454e0249 | 970 | |
7405dc37 | 971 | FUNC_START div0 |
2155b886 RE |
972 | FUNC_ALIAS aeabi_idiv0 div0 |
973 | FUNC_ALIAS aeabi_ldiv0 div0 | |
454e0249 | 974 | |
7405dc37 | 975 | RET |
d5b7b3ae | 976 | |
b3f8d95d MM |
977 | FUNC_END aeabi_ldiv0 |
978 | FUNC_END aeabi_idiv0 | |
496b84c8 | 979 | FUNC_END div0 |
b355a481 | 980 | |
454e0249 | 981 | #endif /* L_divmodsi_tools */ |
6dcd26ea | 982 | /* ------------------------------------------------------------------------ */ |
75d3a15b NC |
983 | #ifdef L_dvmd_lnx |
984 | @ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls | |
985 | ||
d71ebc32 PB |
986 | /* Constants taken from <asm/unistd.h> and <asm/signal.h> */ |
987 | #define SIGFPE 8 | |
988 | #define __NR_SYSCALL_BASE 0x900000 | |
989 | #define __NR_getpid (__NR_SYSCALL_BASE+ 20) | |
990 | #define __NR_kill (__NR_SYSCALL_BASE+ 37) | |
d0f11b16 DJ |
991 | #define __NR_gettid (__NR_SYSCALL_BASE+ 224) |
992 | #define __NR_tkill (__NR_SYSCALL_BASE+ 238) | |
d71ebc32 | 993 | |
496b84c8 | 994 | .code 32 |
7405dc37 | 995 | FUNC_START div0 |
d5b7b3ae | 996 | |
75d3a15b | 997 | stmfd sp!, {r1, lr} |
d0f11b16 | 998 | swi __NR_gettid |
75d3a15b | 999 | cmn r0, #1000 |
d0f11b16 DJ |
1000 | swihs __NR_getpid |
1001 | cmnhs r0, #1000 | |
496b84c8 | 1002 | RETLDM r1 hs |
d0f11b16 | 1003 | mov ip, r0 |
75d3a15b | 1004 | mov r1, #SIGFPE |
d0f11b16 DJ |
1005 | swi __NR_tkill |
1006 | movs r0, r0 | |
1007 | movne r0, ip | |
1008 | swine __NR_kill | |
496b84c8 | 1009 | RETLDM r1 |
7405dc37 | 1010 | |
496b84c8 | 1011 | FUNC_END div0 |
b355a481 | 1012 | |
75d3a15b | 1013 | #endif /* L_dvmd_lnx */ |
6dcd26ea | 1014 | /* ------------------------------------------------------------------------ */ |
dc491742 RE |
1015 | /* Dword shift operations. */ |
1016 | /* All the following Dword shift variants rely on the fact that | |
1017 | shft xxx, Reg | |
1018 | is in fact done as | |
1019 | shft xxx, (Reg & 255) | |
1020 | so for Reg value in (32...63) and (-1...-31) we will get zero (in the | |
1021 | case of logical shifts) or the sign (for asr). */ | |
1022 | ||
1023 | #ifdef __ARMEB__ | |
1024 | #define al r1 | |
1025 | #define ah r0 | |
1026 | #else | |
1027 | #define al r0 | |
1028 | #define ah r1 | |
1029 | #endif | |
1030 | ||
1031 | #ifdef L_lshrdi3 | |
1032 | ||
1033 | FUNC_START lshrdi3 | |
2155b886 | 1034 | FUNC_ALIAS aeabi_llsr lshrdi3 |
b3f8d95d | 1035 | |
dc491742 RE |
1036 | #ifdef __thumb__ |
1037 | lsr al, r2 | |
1038 | mov r3, ah | |
1039 | lsr ah, r2 | |
1040 | mov ip, r3 | |
1041 | sub r2, #32 | |
1042 | lsr r3, r2 | |
1043 | orr al, r3 | |
1044 | neg r2, r2 | |
1045 | mov r3, ip | |
1046 | lsl r3, r2 | |
1047 | orr al, r3 | |
1048 | RET | |
1049 | #else | |
1050 | subs r3, r2, #32 | |
1051 | rsb ip, r2, #32 | |
1052 | movmi al, al, lsr r2 | |
1053 | movpl al, ah, lsr r3 | |
1054 | orrmi al, al, ah, lsl ip | |
1055 | mov ah, ah, lsr r2 | |
1056 | RET | |
1057 | #endif | |
b3f8d95d | 1058 | FUNC_END aeabi_llsr |
dc491742 RE |
1059 | FUNC_END lshrdi3 |
1060 | ||
1061 | #endif | |
1062 | ||
1063 | #ifdef L_ashrdi3 | |
1064 | ||
1065 | FUNC_START ashrdi3 | |
2155b886 | 1066 | FUNC_ALIAS aeabi_lasr ashrdi3 |
b3f8d95d | 1067 | |
dc491742 RE |
1068 | #ifdef __thumb__ |
1069 | lsr al, r2 | |
1070 | mov r3, ah | |
1071 | asr ah, r2 | |
1072 | sub r2, #32 | |
1073 | @ If r2 is negative at this point the following step would OR | |
1074 | @ the sign bit into all of AL. That's not what we want... | |
1075 | bmi 1f | |
1076 | mov ip, r3 | |
1077 | asr r3, r2 | |
1078 | orr al, r3 | |
1079 | mov r3, ip | |
1080 | 1: | |
1081 | neg r2, r2 | |
1082 | lsl r3, r2 | |
1083 | orr al, r3 | |
1084 | RET | |
1085 | #else | |
1086 | subs r3, r2, #32 | |
1087 | rsb ip, r2, #32 | |
1088 | movmi al, al, lsr r2 | |
1089 | movpl al, ah, asr r3 | |
1090 | orrmi al, al, ah, lsl ip | |
1091 | mov ah, ah, asr r2 | |
1092 | RET | |
1093 | #endif | |
1094 | ||
b3f8d95d | 1095 | FUNC_END aeabi_lasr |
dc491742 RE |
1096 | FUNC_END ashrdi3 |
1097 | ||
1098 | #endif | |
1099 | ||
1100 | #ifdef L_ashldi3 | |
1101 | ||
1102 | FUNC_START ashldi3 | |
2155b886 | 1103 | FUNC_ALIAS aeabi_llsl ashldi3 |
b3f8d95d | 1104 | |
dc491742 RE |
1105 | #ifdef __thumb__ |
1106 | lsl ah, r2 | |
1107 | mov r3, al | |
1108 | lsl al, r2 | |
1109 | mov ip, r3 | |
1110 | sub r2, #32 | |
1111 | lsl r3, r2 | |
1112 | orr ah, r3 | |
1113 | neg r2, r2 | |
1114 | mov r3, ip | |
1115 | lsr r3, r2 | |
1116 | orr ah, r3 | |
1117 | RET | |
1118 | #else | |
1119 | subs r3, r2, #32 | |
1120 | rsb ip, r2, #32 | |
1121 | movmi ah, ah, lsl r2 | |
1122 | movpl ah, al, lsl r3 | |
1123 | orrmi ah, ah, al, lsr ip | |
1124 | mov al, al, lsl r2 | |
1125 | RET | |
1126 | #endif | |
b3f8d95d | 1127 | FUNC_END aeabi_llsl |
dc491742 RE |
1128 | FUNC_END ashldi3 |
1129 | ||
1130 | #endif | |
1131 | ||
1132 | /* ------------------------------------------------------------------------ */ | |
75d3a15b NC |
1133 | /* These next two sections are here despite the fact that they contain Thumb |
1134 | assembler because their presence allows interworked code to be linked even | |
1135 | when the GCC library is this one. */ | |
1136 | ||
c84df4c5 NC |
1137 | /* Do not build the interworking functions when the target architecture does |
1138 | not support Thumb instructions. (This can be a multilib option). */ | |
e0d4a859 PB |
1139 | #if defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__\ |
1140 | || defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ \ | |
1141 | || __ARM_ARCH__ >= 6 | |
1142 | ||
1143 | #if defined L_call_via_rX | |
75d3a15b NC |
1144 | |
1145 | /* These labels & instructions are used by the Arm/Thumb interworking code. | |
1146 | The address of function to be called is loaded into a register and then | |
1147 | one of these labels is called via a BL instruction. This puts the | |
1148 | return address into the link register with the bottom bit set, and the | |
1149 | code here switches to the correct mode before executing the function. */ | |
1150 | ||
1151 | .text | |
1152 | .align 0 | |
ec8aac6f | 1153 | .force_thumb |
7405dc37 | 1154 | |
75d3a15b | 1155 | .macro call_via register |
6dcd26ea RE |
1156 | THUMB_FUNC_START _call_via_\register |
1157 | ||
75d3a15b NC |
1158 | bx \register |
1159 | nop | |
2a5307b1 NC |
1160 | |
1161 | SIZE (_call_via_\register) | |
75d3a15b NC |
1162 | .endm |
1163 | ||
1164 | call_via r0 | |
1165 | call_via r1 | |
1166 | call_via r2 | |
1167 | call_via r3 | |
1168 | call_via r4 | |
1169 | call_via r5 | |
1170 | call_via r6 | |
1171 | call_via r7 | |
1172 | call_via r8 | |
1173 | call_via r9 | |
1174 | call_via sl | |
1175 | call_via fp | |
1176 | call_via ip | |
1177 | call_via sp | |
1178 | call_via lr | |
1179 | ||
1180 | #endif /* L_call_via_rX */ | |
e0d4a859 PB |
1181 | |
1182 | #if defined L_interwork_call_via_rX | |
7405dc37 | 1183 | |
75d3a15b NC |
1184 | /* These labels & instructions are used by the Arm/Thumb interworking code, |
1185 | when the target address is in an unknown instruction set. The address | |
1186 | of function to be called is loaded into a register and then one of these | |
1187 | labels is called via a BL instruction. This puts the return address | |
1188 | into the link register with the bottom bit set, and the code here | |
1189 | switches to the correct mode before executing the function. Unfortunately | |
1190 | the target code cannot be relied upon to return via a BX instruction, so | |
1191 | instead we have to store the resturn address on the stack and allow the | |
1192 | called function to return here instead. Upon return we recover the real | |
a2503645 RS |
1193 | return address and use a BX to get back to Thumb mode. |
1194 | ||
1195 | There are three variations of this code. The first, | |
1196 | _interwork_call_via_rN(), will push the return address onto the | |
1197 | stack and pop it in _arm_return(). It should only be used if all | |
1198 | arguments are passed in registers. | |
1199 | ||
1200 | The second, _interwork_r7_call_via_rN(), instead stores the return | |
1201 | address at [r7, #-4]. It is the caller's responsibility to ensure | |
1202 | that this address is valid and contains no useful data. | |
1203 | ||
1204 | The third, _interwork_r11_call_via_rN(), works in the same way but | |
1205 | uses r11 instead of r7. It is useful if the caller does not really | |
1206 | need a frame pointer. */ | |
75d3a15b NC |
1207 | |
1208 | .text | |
1209 | .align 0 | |
1210 | ||
1211 | .code 32 | |
2a5307b1 | 1212 | .globl _arm_return |
d0f11b16 DJ |
1213 | LSYM(Lstart_arm_return): |
1214 | cfi_start LSYM(Lstart_arm_return) LSYM(Lend_arm_return) | |
1215 | cfi_push 0, 0xe, -0x8, 0x8 | |
1216 | nop @ This nop is for the benefit of debuggers, so that | |
1217 | @ backtraces will use the correct unwind information. | |
496b84c8 | 1218 | _arm_return: |
d0f11b16 DJ |
1219 | RETLDM unwind=LSYM(Lstart_arm_return) |
1220 | cfi_end LSYM(Lend_arm_return) | |
a2503645 RS |
1221 | |
1222 | .globl _arm_return_r7 | |
1223 | _arm_return_r7: | |
1224 | ldr lr, [r7, #-4] | |
1225 | bx lr | |
1226 | ||
1227 | .globl _arm_return_r11 | |
1228 | _arm_return_r11: | |
1229 | ldr lr, [r11, #-4] | |
1230 | bx lr | |
1231 | ||
1232 | .macro interwork_with_frame frame, register, name, return | |
1233 | .code 16 | |
1234 | ||
1235 | THUMB_FUNC_START \name | |
1236 | ||
1237 | bx pc | |
1238 | nop | |
1239 | ||
1240 | .code 32 | |
1241 | tst \register, #1 | |
1242 | streq lr, [\frame, #-4] | |
1243 | adreq lr, _arm_return_\frame | |
1244 | bx \register | |
1245 | ||
1246 | SIZE (\name) | |
1247 | .endm | |
75d3a15b | 1248 | |
496b84c8 RE |
1249 | .macro interwork register |
1250 | .code 16 | |
6dcd26ea RE |
1251 | |
1252 | THUMB_FUNC_START _interwork_call_via_\register | |
1253 | ||
496b84c8 | 1254 | bx pc |
75d3a15b | 1255 | nop |
496b84c8 RE |
1256 | |
1257 | .code 32 | |
1258 | .globl LSYM(Lchange_\register) | |
1259 | LSYM(Lchange_\register): | |
75d3a15b | 1260 | tst \register, #1 |
d0f11b16 | 1261 | streq lr, [sp, #-8]! |
75d3a15b NC |
1262 | adreq lr, _arm_return |
1263 | bx \register | |
2a5307b1 NC |
1264 | |
1265 | SIZE (_interwork_call_via_\register) | |
a2503645 RS |
1266 | |
1267 | interwork_with_frame r7,\register,_interwork_r7_call_via_\register | |
1268 | interwork_with_frame r11,\register,_interwork_r11_call_via_\register | |
75d3a15b NC |
1269 | .endm |
1270 | ||
1271 | interwork r0 | |
1272 | interwork r1 | |
1273 | interwork r2 | |
1274 | interwork r3 | |
1275 | interwork r4 | |
1276 | interwork r5 | |
1277 | interwork r6 | |
1278 | interwork r7 | |
1279 | interwork r8 | |
1280 | interwork r9 | |
1281 | interwork sl | |
1282 | interwork fp | |
1283 | interwork ip | |
1284 | interwork sp | |
2a5307b1 | 1285 | |
6dcd26ea | 1286 | /* The LR case has to be handled a little differently... */ |
2a5307b1 | 1287 | .code 16 |
6dcd26ea RE |
1288 | |
1289 | THUMB_FUNC_START _interwork_call_via_lr | |
1290 | ||
2a5307b1 NC |
1291 | bx pc |
1292 | nop | |
1293 | ||
1294 | .code 32 | |
1295 | .globl .Lchange_lr | |
1296 | .Lchange_lr: | |
1297 | tst lr, #1 | |
d0f11b16 | 1298 | stmeqdb r13!, {lr, pc} |
2a5307b1 NC |
1299 | mov ip, lr |
1300 | adreq lr, _arm_return | |
1301 | bx ip | |
1302 | ||
1303 | SIZE (_interwork_call_via_lr) | |
1304 | ||
75d3a15b | 1305 | #endif /* L_interwork_call_via_rX */ |
e0d4a859 | 1306 | #endif /* Arch supports thumb. */ |
4202ce82 | 1307 | |
f9a02408 | 1308 | #ifndef __symbian__ |
4202ce82 | 1309 | #include "ieee754-df.S" |
4202ce82 | 1310 | #include "ieee754-sf.S" |
b3f8d95d | 1311 | #include "bpabi.S" |
617a1b71 | 1312 | #include "libunwind.S" |
f9a02408 | 1313 | #endif /* __symbian__ */ |