Fix typo: LSM instead of LSYM.
[official-gcc.git] / gcc / config / arm / lib1funcs.asm
blob03b71a835baa06d0de6fa6c7a4095ac1ea2f2144
1 @ libgcc routines for ARM cpu.
2 @ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk)
4 /* Copyright 1995, 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
6 This file is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file. (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
18 executable.)
20 This file is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING. If not, write to
27 the Free Software Foundation, 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA. */
29 /* ------------------------------------------------------------------------ */
31 /* We need to know what prefix to add to function names. */
33 #ifndef __USER_LABEL_PREFIX__
34 #error __USER_LABEL_PREFIX__ not defined
35 #endif
37 /* ANSI concatenation macros. */
39 #define CONCAT1(a, b) CONCAT2(a, b)
40 #define CONCAT2(a, b) a ## b
42 /* Use the right prefix for global labels. */
44 #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
46 #ifdef __ELF__
47 #ifdef __thumb__
48 #define __PLT__ /* Not supported in Thumb assembler (for now). */
49 #else
50 #define __PLT__ (PLT)
51 #endif
52 #define TYPE(x) .type SYM(x),function
53 #define SIZE(x) .size SYM(x), . - SYM(x)
54 #define LSYM(x) .x
55 #else
56 #define __PLT__
57 #define TYPE(x)
58 #define SIZE(x)
59 #define LSYM(x) x
60 #endif
62 /* Function end macros. Variants for 26 bit APCS and interworking. */
64 #ifdef __APCS_26__
65 # define RET movs pc, lr
66 # define RETc(x) mov##x##s pc, lr
67 # define RETCOND ^
68 .macro ARM_LDIV0
69 LSYM(Ldiv0):
70 str lr, [sp, #-4]!
71 bl SYM (__div0) __PLT__
72 mov r0, #0 @ About as wrong as it could be.
73 ldmia sp!, {pc}^
74 .endm
75 #else
76 # ifdef __THUMB_INTERWORK__
77 # define RET bx lr
78 # define RETc(x) bx##x lr
79 .macro THUMB_LDIV0
80 LSYM(Ldiv0):
81 push { lr }
82 bl SYM (__div0)
83 mov r0, #0 @ About as wrong as it could be.
84 pop { r1 }
85 bx r1
86 .endm
87 .macro ARM_LDIV0
88 LSYM(Ldiv0):
89 str lr, [sp, #-4]!
90 bl SYM (__div0) __PLT__
91 mov r0, #0 @ About as wrong as it could be.
92 ldr lr, [sp], #4
93 bx lr
94 .endm
95 # else
96 # define RET mov pc, lr
97 # define RETc(x) mov##x pc, lr
98 .macro THUMB_LDIV0
99 LSYM(Ldiv0):
100 push { lr }
101 bl SYM (__div0)
102 mov r0, #0 @ About as wrong as it could be.
103 pop { pc }
104 .endm
105 .macro ARM_LDIV0
106 LSYM(Ldiv0):
107 str lr, [sp, #-4]!
108 bl SYM (__div0) __PLT__
109 mov r0, #0 @ About as wrong as it could be.
110 ldmia sp!, {pc}
111 .endm
112 # endif
113 # define RETCOND
114 #endif
116 .macro FUNC_END name
117 LSYM(Ldiv0):
118 #ifdef __thumb__
119 THUMB_LDIV0
120 #else
121 ARM_LDIV0
122 #endif
123 SIZE (__\name)
124 .endm
126 .macro THUMB_FUNC_START name
127 .globl SYM (\name)
128 TYPE (\name)
129 .thumb_func
130 SYM (\name):
131 .endm
133 /* Function start macros. Variants for ARM and Thumb. */
135 #ifdef __thumb__
136 #define THUMB_FUNC .thumb_func
137 #define THUMB_CODE .force_thumb
138 #else
139 #define THUMB_FUNC
140 #define THUMB_CODE
141 #endif
143 .macro FUNC_START name
144 .text
145 .globl SYM (__\name)
146 TYPE (__\name)
147 .align 0
148 THUMB_CODE
149 THUMB_FUNC
150 SYM (__\name):
151 .endm
153 /* Register aliases. */
155 work .req r4 @ XXXX is this safe ?
156 dividend .req r0
157 divisor .req r1
158 overdone .req r2
159 result .req r2
160 curbit .req r3
161 ip .req r12
162 sp .req r13
163 lr .req r14
164 pc .req r15
166 /* ------------------------------------------------------------------------ */
167 /* Bodies of the divsion and modulo routines. */
168 /* ------------------------------------------------------------------------ */
169 .macro ARM_DIV_MOD_BODY modulo
170 LSYM(Loop1):
171 @ Unless the divisor is very big, shift it up in multiples of
172 @ four bits, since this is the amount of unwinding in the main
173 @ division loop. Continue shifting until the divisor is
174 @ larger than the dividend.
175 cmp divisor, #0x10000000
176 cmplo divisor, dividend
177 movlo divisor, divisor, lsl #4
178 movlo curbit, curbit, lsl #4
179 blo LSYM(Loop1)
181 LSYM(Lbignum):
182 @ For very big divisors, we must shift it a bit at a time, or
183 @ we will be in danger of overflowing.
184 cmp divisor, #0x80000000
185 cmplo divisor, dividend
186 movlo divisor, divisor, lsl #1
187 movlo curbit, curbit, lsl #1
188 blo LSYM(Lbignum)
190 LSYM(Loop3):
191 @ Test for possible subtractions. On the final pass, this may
192 @ subtract too much from the dividend ...
194 .if \modulo
195 @ ... so keep track of which subtractions are done in OVERDONE.
196 @ We can fix them up afterwards.
197 mov overdone, #0
198 cmp dividend, divisor
199 subhs dividend, dividend, divisor
200 cmp dividend, divisor, lsr #1
201 subhs dividend, dividend, divisor, lsr #1
202 orrhs overdone, overdone, curbit, ror #1
203 cmp dividend, divisor, lsr #2
204 subhs dividend, dividend, divisor, lsr #2
205 orrhs overdone, overdone, curbit, ror #2
206 cmp dividend, divisor, lsr #3
207 subhs dividend, dividend, divisor, lsr #3
208 orrhs overdone, overdone, curbit, ror #3
209 mov ip, curbit
210 .else
211 @ ... so keep track of which subtractions are done in RESULT.
212 @ The result will be ok, since the "bit" will have been
213 @ shifted out at the bottom.
214 cmp dividend, divisor
215 subhs dividend, dividend, divisor
216 orrhs result, result, curbit
217 cmp dividend, divisor, lsr #1
218 subhs dividend, dividend, divisor, lsr #1
219 orrhs result, result, curbit, lsr #1
220 cmp dividend, divisor, lsr #2
221 subhs dividend, dividend, divisor, lsr #2
222 orrhs result, result, curbit, lsr #2
223 cmp dividend, divisor, lsr #3
224 subhs dividend, dividend, divisor, lsr #3
225 orrhs result, result, curbit, lsr #3
226 .endif
228 cmp dividend, #0 @ Early termination?
229 movnes curbit, curbit, lsr #4 @ No, any more bits to do?
230 movne divisor, divisor, lsr #4
231 bne LSYM(Loop3)
233 .if \modulo
234 LSYM(Lfixup_dividend):
235 @ Any subtractions that we should not have done will be recorded in
236 @ the top three bits of OVERDONE. Exactly which were not needed
237 @ are governed by the position of the bit, stored in IP.
238 ands overdone, overdone, #0xe0000000
239 @ If we terminated early, because dividend became zero, then the
240 @ bit in ip will not be in the bottom nibble, and we should not
241 @ perform the additions below. We must test for this though
242 @ (rather relying upon the TSTs to prevent the additions) since
243 @ the bit in ip could be in the top two bits which might then match
244 @ with one of the smaller RORs.
245 tstne ip, #0x7
246 beq LSYM(Lgot_result)
247 tst overdone, ip, ror #3
248 addne dividend, dividend, divisor, lsr #3
249 tst overdone, ip, ror #2
250 addne dividend, dividend, divisor, lsr #2
251 tst overdone, ip, ror #1
252 addne dividend, dividend, divisor, lsr #1
253 .endif
255 LSYM(Lgot_result):
256 .endm
257 /* ------------------------------------------------------------------------ */
258 .macro THUMB_DIV_MOD_BODY modulo
259 @ Load the constant 0x10000000 into our work register.
260 mov work, #1
261 lsl work, #28
262 LSYM(Loop1):
263 @ Unless the divisor is very big, shift it up in multiples of
264 @ four bits, since this is the amount of unwinding in the main
265 @ division loop. Continue shifting until the divisor is
266 @ larger than the dividend.
267 cmp divisor, work
268 bhs LSYM(Lbignum)
269 cmp divisor, dividend
270 bhs LSYM(Lbignum)
271 lsl divisor, #4
272 lsl curbit, #4
273 b LSYM(Loop1)
274 LSYM(Lbignum):
275 @ Set work to 0x80000000
276 lsl work, #3
277 LSYM(Loop2):
278 @ For very big divisors, we must shift it a bit at a time, or
279 @ we will be in danger of overflowing.
280 cmp divisor, work
281 bhs LSYM(Loop3)
282 cmp divisor, dividend
283 bhs LSYM(Loop3)
284 lsl divisor, #1
285 lsl curbit, #1
286 b LSYM(Loop2)
287 LSYM(Loop3):
288 @ Test for possible subtractions ...
289 .if \modulo
290 @ ... On the final pass, this may subtract too much from the dividend,
291 @ so keep track of which subtractions are done, we can fix them up
292 @ afterwards.
293 mov overdone, #0
294 cmp dividend, divisor
295 blo LSYM(Lover1)
296 sub dividend, dividend, divisor
297 LSYM(Lover1):
298 lsr work, divisor, #1
299 cmp dividend, work
300 blo LSYM(Lover2)
301 sub dividend, dividend, work
302 mov ip, curbit
303 mov work, #1
304 ror curbit, work
305 orr overdone, curbit
306 mov curbit, ip
307 LSYM(Lover2):
308 lsr work, divisor, #2
309 cmp dividend, work
310 blo LSYM(Lover3)
311 sub dividend, dividend, work
312 mov ip, curbit
313 mov work, #2
314 ror curbit, work
315 orr overdone, curbit
316 mov curbit, ip
317 LSYM(Lover3):
318 lsr work, divisor, #3
319 cmp dividend, work
320 blo LSYM(Lover4)
321 sub dividend, dividend, work
322 mov ip, curbit
323 mov work, #3
324 ror curbit, work
325 orr overdone, curbit
326 mov curbit, ip
327 LSYM(Lover4):
328 mov ip, curbit
329 .else
330 @ ... and note which bits are done in the result. On the final pass,
331 @ this may subtract too much from the dividend, but the result will be ok,
332 @ since the "bit" will have been shifted out at the bottom.
333 cmp dividend, divisor
334 blo LSYM(Lover1)
335 sub dividend, dividend, divisor
336 orr result, result, curbit
337 LSYM(Lover1):
338 lsr work, divisor, #1
339 cmp dividend, work
340 blo LSYM(Lover2)
341 sub dividend, dividend, work
342 lsr work, curbit, #1
343 orr result, work
344 LSYM(Lover2):
345 lsr work, divisor, #2
346 cmp dividend, work
347 blo LSYM(Lover3)
348 sub dividend, dividend, work
349 lsr work, curbit, #2
350 orr result, work
351 LSYM(Lover3):
352 lsr work, divisor, #3
353 cmp dividend, work
354 blo LSYM(Lover4)
355 sub dividend, dividend, work
356 lsr work, curbit, #3
357 orr result, work
358 LSYM(Lover4):
359 .endif
361 cmp dividend, #0 @ Early termination?
362 beq LSYM(Lover5)
363 lsr curbit, #4 @ No, any more bits to do?
364 beq LSYM(Lover5)
365 lsr divisor, #4
366 b LSYM(Loop3)
367 LSYM(Lover5):
368 .if \modulo
369 @ Any subtractions that we should not have done will be recorded in
370 @ the top three bits of "overdone". Exactly which were not needed
371 @ are governed by the position of the bit, stored in ip.
372 mov work, #0xe
373 lsl work, #28
374 and overdone, work
375 beq LSYM(Lgot_result)
377 @ If we terminated early, because dividend became zero, then the
378 @ bit in ip will not be in the bottom nibble, and we should not
379 @ perform the additions below. We must test for this though
380 @ (rather relying upon the TSTs to prevent the additions) since
381 @ the bit in ip could be in the top two bits which might then match
382 @ with one of the smaller RORs.
383 mov curbit, ip
384 mov work, #0x7
385 tst curbit, work
386 beq LSYM(Lgot_result)
388 mov curbit, ip
389 mov work, #3
390 ror curbit, work
391 tst overdone, curbit
392 beq LSYM(Lover6)
393 lsr work, divisor, #3
394 add dividend, work
395 LSYM(Lover6):
396 mov curbit, ip
397 mov work, #2
398 ror curbit, work
399 tst overdone, curbit
400 beq LSYM(Lover7)
401 lsr work, divisor, #2
402 add dividend, work
403 LSYM(Lover7):
404 mov curbit, ip
405 mov work, #1
406 ror curbit, work
407 tst overdone, curbit
408 beq LSYM(Lgot_result)
409 lsr work, divisor, #1
410 add dividend, work
411 .endif
412 LSYM(Lgot_result):
413 .endm
414 /* ------------------------------------------------------------------------ */
415 /* Start of the Real Functions */
416 /* ------------------------------------------------------------------------ */
417 #ifdef L_udivsi3
419 FUNC_START udivsi3
421 #ifdef __thumb__
423 cmp divisor, #0
424 beq LSYM(Ldiv0)
425 mov curbit, #1
426 mov result, #0
428 push { work }
429 cmp dividend, divisor
430 blo LSYM(Lgot_result)
432 THUMB_DIV_MOD_BODY 0
434 mov r0, result
435 pop { work }
438 #else /* ARM version. */
440 cmp divisor, #0
441 beq LSYM(Ldiv0)
442 mov curbit, #1
443 mov result, #0
444 cmp dividend, divisor
445 blo LSYM(Lgot_result)
447 ARM_DIV_MOD_BODY 0
449 mov r0, result
450 RET
452 #endif /* ARM version */
454 FUNC_END udivsi3
456 #endif /* L_udivsi3 */
457 /* ------------------------------------------------------------------------ */
458 #ifdef L_umodsi3
460 FUNC_START umodsi3
462 #ifdef __thumb__
464 cmp divisor, #0
465 beq LSYM(Ldiv0)
466 mov curbit, #1
467 cmp dividend, divisor
468 bhs LSYM(Lover10)
469 RET
471 LSYM(Lover10):
472 push { work }
474 THUMB_DIV_MOD_BODY 1
476 pop { work }
479 #else /* ARM version. */
481 cmp divisor, #0
482 beq LSYM(Ldiv0)
483 cmp divisor, #1
484 cmpne dividend, divisor
485 moveq dividend, #0
486 RETc(lo)
487 mov curbit, #1
489 ARM_DIV_MOD_BODY 1
491 RET
493 #endif /* ARM version. */
495 FUNC_END umodsi3
497 #endif /* L_umodsi3 */
498 /* ------------------------------------------------------------------------ */
499 #ifdef L_divsi3
501 FUNC_START divsi3
503 #ifdef __thumb__
504 cmp divisor, #0
505 beq LSYM(Ldiv0)
507 push { work }
508 mov work, dividend
509 eor work, divisor @ Save the sign of the result.
510 mov ip, work
511 mov curbit, #1
512 mov result, #0
513 cmp divisor, #0
514 bpl LSYM(Lover10)
515 neg divisor, divisor @ Loops below use unsigned.
516 LSYM(Lover10):
517 cmp dividend, #0
518 bpl LSYM(Lover11)
519 neg dividend, dividend
520 LSYM(Lover11):
521 cmp dividend, divisor
522 blo LSYM(Lgot_result)
524 THUMB_DIV_MOD_BODY 0
526 mov r0, result
527 mov work, ip
528 cmp work, #0
529 bpl LSYM(Lover12)
530 neg r0, r0
531 LSYM(Lover12):
532 pop { work }
535 #else /* ARM version. */
537 eor ip, dividend, divisor @ Save the sign of the result.
538 mov curbit, #1
539 mov result, #0
540 cmp divisor, #0
541 rsbmi divisor, divisor, #0 @ Loops below use unsigned.
542 beq LSYM(Ldiv0)
543 cmp dividend, #0
544 rsbmi dividend, dividend, #0
545 cmp dividend, divisor
546 blo LSYM(Lgot_result)
548 ARM_DIV_MOD_BODY 0
550 mov r0, result
551 cmp ip, #0
552 rsbmi r0, r0, #0
553 RET
555 #endif /* ARM version */
557 FUNC_END divsi3
559 #endif /* L_divsi3 */
560 /* ------------------------------------------------------------------------ */
561 #ifdef L_modsi3
563 FUNC_START modsi3
565 #ifdef __thumb__
567 mov curbit, #1
568 cmp divisor, #0
569 beq LSYM(Ldiv0)
570 bpl LSYM(Lover10)
571 neg divisor, divisor @ Loops below use unsigned.
572 LSYM(Lover10):
573 push { work }
574 @ Need to save the sign of the dividend, unfortunately, we need
575 @ work later on. Must do this after saving the original value of
576 @ the work register, because we will pop this value off first.
577 push { dividend }
578 cmp dividend, #0
579 bpl LSYM(Lover11)
580 neg dividend, dividend
581 LSYM(Lover11):
582 cmp dividend, divisor
583 blo LSYM(Lgot_result)
585 THUMB_DIV_MOD_BODY 1
587 pop { work }
588 cmp work, #0
589 bpl LSYM(Lover12)
590 neg dividend, dividend
591 LSYM(Lover12):
592 pop { work }
593 RET
595 #else /* ARM version. */
597 cmp divisor, #0
598 rsbmi divisor, divisor, #0 @ Loops below use unsigned.
599 beq LSYM(Ldiv0)
600 @ Need to save the sign of the dividend, unfortunately, we need
601 @ ip later on; this is faster than pushing lr and using that.
602 str dividend, [sp, #-4]!
603 cmp dividend, #0 @ Test dividend against zero
604 rsbmi dividend, dividend, #0 @ If negative make positive
605 cmp dividend, divisor @ else if zero return zero
606 blo LSYM(Lgot_result) @ if smaller return dividend
607 mov curbit, #1
609 ARM_DIV_MOD_BODY 1
611 ldr ip, [sp], #4
612 cmp ip, #0
613 rsbmi dividend, dividend, #0
614 RET
616 #endif /* ARM version */
618 FUNC_END modsi3
620 #endif /* L_modsi3 */
621 /* ------------------------------------------------------------------------ */
622 #ifdef L_dvmd_tls
624 FUNC_START div0
628 SIZE (__div0)
630 #endif /* L_divmodsi_tools */
631 /* ------------------------------------------------------------------------ */
632 #ifdef L_dvmd_lnx
633 @ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls
635 /* Constants taken from <asm/unistd.h> and <asm/signal.h> */
636 #define SIGFPE 8
637 #define __NR_SYSCALL_BASE 0x900000
638 #define __NR_getpid (__NR_SYSCALL_BASE+ 20)
639 #define __NR_kill (__NR_SYSCALL_BASE+ 37)
641 FUNC_START div0
643 stmfd sp!, {r1, lr}
644 swi __NR_getpid
645 cmn r0, #1000
646 ldmhsfd sp!, {r1, pc}RETCOND @ not much we can do
647 mov r1, #SIGFPE
648 swi __NR_kill
649 #ifdef __THUMB_INTERWORK__
650 ldmfd sp!, {r1, lr}
651 bx lr
652 #else
653 ldmfd sp!, {r1, pc}RETCOND
654 #endif
656 SIZE (__div0)
658 #endif /* L_dvmd_lnx */
659 /* ------------------------------------------------------------------------ */
660 /* These next two sections are here despite the fact that they contain Thumb
661 assembler because their presence allows interworked code to be linked even
662 when the GCC library is this one. */
664 /* Do not build the interworking functions when the target architecture does
665 not support Thumb instructions. (This can be a multilib option). */
666 #if defined L_call_via_rX && (defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__)
668 /* These labels & instructions are used by the Arm/Thumb interworking code.
669 The address of function to be called is loaded into a register and then
670 one of these labels is called via a BL instruction. This puts the
671 return address into the link register with the bottom bit set, and the
672 code here switches to the correct mode before executing the function. */
674 .text
675 .align 0
676 .force_thumb
678 .macro call_via register
679 THUMB_FUNC_START _call_via_\register
681 bx \register
684 SIZE (_call_via_\register)
685 .endm
687 call_via r0
688 call_via r1
689 call_via r2
690 call_via r3
691 call_via r4
692 call_via r5
693 call_via r6
694 call_via r7
695 call_via r8
696 call_via r9
697 call_via sl
698 call_via fp
699 call_via ip
700 call_via sp
701 call_via lr
703 #endif /* L_call_via_rX */
704 /* ------------------------------------------------------------------------ */
705 /* Do not build the interworking functions when the target architecture does
706 not support Thumb instructions. (This can be a multilib option). */
707 #if defined L_interwork_call_via_rX && (defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__)
709 /* These labels & instructions are used by the Arm/Thumb interworking code,
710 when the target address is in an unknown instruction set. The address
711 of function to be called is loaded into a register and then one of these
712 labels is called via a BL instruction. This puts the return address
713 into the link register with the bottom bit set, and the code here
714 switches to the correct mode before executing the function. Unfortunately
715 the target code cannot be relied upon to return via a BX instruction, so
716 instead we have to store the resturn address on the stack and allow the
717 called function to return here instead. Upon return we recover the real
718 return address and use a BX to get back to Thumb mode. */
720 .text
721 .align 0
723 .code 32
724 .globl _arm_return
725 _arm_return:
726 ldmia r13!, {r12}
727 bx r12
728 .code 16
730 .macro interwork register
731 .code 16
733 THUMB_FUNC_START _interwork_call_via_\register
735 bx pc
738 .code 32
739 .globl .Lchange_\register
740 .Lchange_\register:
741 tst \register, #1
742 stmeqdb r13!, {lr}
743 adreq lr, _arm_return
744 bx \register
746 SIZE (_interwork_call_via_\register)
747 .endm
749 interwork r0
750 interwork r1
751 interwork r2
752 interwork r3
753 interwork r4
754 interwork r5
755 interwork r6
756 interwork r7
757 interwork r8
758 interwork r9
759 interwork sl
760 interwork fp
761 interwork ip
762 interwork sp
764 /* The LR case has to be handled a little differently... */
765 .code 16
767 THUMB_FUNC_START _interwork_call_via_lr
769 bx pc
772 .code 32
773 .globl .Lchange_lr
774 .Lchange_lr:
775 tst lr, #1
776 stmeqdb r13!, {lr}
777 mov ip, lr
778 adreq lr, _arm_return
779 bx ip
781 SIZE (_interwork_call_via_lr)
783 #endif /* L_interwork_call_via_rX */