190075Sobrien@ libgcc routines for ARM cpu.
290075Sobrien@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk)
390075Sobrien
4169689Skan/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005
5132718Skan   Free Software Foundation, Inc.
690075Sobrien
790075SobrienThis file is free software; you can redistribute it and/or modify it
890075Sobrienunder the terms of the GNU General Public License as published by the
990075SobrienFree Software Foundation; either version 2, or (at your option) any
1090075Sobrienlater version.
1190075Sobrien
1290075SobrienIn addition to the permissions in the GNU General Public License, the
1390075SobrienFree Software Foundation gives you unlimited permission to link the
1490075Sobriencompiled version of this file into combinations with other programs,
1590075Sobrienand to distribute those combinations without any restriction coming
1690075Sobrienfrom the use of this file.  (The General Public License restrictions
1790075Sobriendo apply in other respects; for example, they cover modification of
1890075Sobrienthe file, and distribution when not linked into a combine
1990075Sobrienexecutable.)
2090075Sobrien
2190075SobrienThis file is distributed in the hope that it will be useful, but
2290075SobrienWITHOUT ANY WARRANTY; without even the implied warranty of
2390075SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2490075SobrienGeneral Public License for more details.
2590075Sobrien
2690075SobrienYou should have received a copy of the GNU General Public License
2790075Sobrienalong with this program; see the file COPYING.  If not, write to
28169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
29169689SkanBoston, MA 02110-1301, USA.  */
3090075Sobrien/* ------------------------------------------------------------------------ */
3190075Sobrien
3290075Sobrien/* We need to know what prefix to add to function names.  */
3390075Sobrien
3490075Sobrien#ifndef __USER_LABEL_PREFIX__
3590075Sobrien#error  __USER_LABEL_PREFIX__ not defined
3690075Sobrien#endif
3790075Sobrien
3890075Sobrien/* ANSI concatenation macros.  */
3990075Sobrien
4090075Sobrien#define CONCAT1(a, b) CONCAT2(a, b)
4190075Sobrien#define CONCAT2(a, b) a ## b
4290075Sobrien
4390075Sobrien/* Use the right prefix for global labels.  */
4490075Sobrien
4590075Sobrien#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
4690075Sobrien
4790075Sobrien#ifdef __ELF__
4890075Sobrien#ifdef __thumb__
4990075Sobrien#define __PLT__  /* Not supported in Thumb assembler (for now).  */
5090075Sobrien#else
5190075Sobrien#define __PLT__ (PLT)
5290075Sobrien#endif
5390075Sobrien#define TYPE(x) .type SYM(x),function
5490075Sobrien#define SIZE(x) .size SYM(x), . - SYM(x)
55132718Skan#define LSYM(x) .x
5690075Sobrien#else
5790075Sobrien#define __PLT__
5890075Sobrien#define TYPE(x)
5990075Sobrien#define SIZE(x)
60132718Skan#define LSYM(x) x
6190075Sobrien#endif
6290075Sobrien
63169689Skan/* Function end macros.  Variants for interworking.  */
6490075Sobrien
65132718Skan@ This selects the minimum architecture level required.
66132718Skan#define __ARM_ARCH__ 3
67132718Skan
68132718Skan#if defined(__ARM_ARCH_3M__) || defined(__ARM_ARCH_4__) \
69132718Skan	|| defined(__ARM_ARCH_4T__)
70132718Skan/* We use __ARM_ARCH__ set to 4 here, but in reality it's any processor with
71132718Skan   long multiply instructions.  That includes v3M.  */
72132718Skan# undef __ARM_ARCH__
73132718Skan# define __ARM_ARCH__ 4
74132718Skan#endif
75132718Skan	
76132718Skan#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
77169689Skan	|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
78169689Skan	|| defined(__ARM_ARCH_5TEJ__)
79132718Skan# undef __ARM_ARCH__
80132718Skan# define __ARM_ARCH__ 5
81132718Skan#endif
82132718Skan
83169689Skan#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
84169689Skan	|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
85169689Skan	|| defined(__ARM_ARCH_6ZK__)
86169689Skan# undef __ARM_ARCH__
87169689Skan# define __ARM_ARCH__ 6
88169689Skan#endif
89132718Skan
90169689Skan#ifndef __ARM_ARCH__
91169689Skan#error Unable to determine architecture.
92169689Skan#endif
93132718Skan
94169689Skan/* How to return from a function call depends on the architecture variant.  */
95132718Skan
96169689Skan#if (__ARM_ARCH__ > 4) || defined(__ARM_ARCH_4T__)
97132718Skan
98132718Skan# define RET		bx	lr
99132718Skan# define RETc(x)	bx##x	lr
100132718Skan
101169689Skan/* Special precautions for interworking on armv4t.  */
102169689Skan# if (__ARM_ARCH__ == 4)
103132718Skan
104169689Skan/* Always use bx, not ldr pc.  */
105169689Skan#  if (defined(__thumb__) || defined(__THUMB_INTERWORK__))
106169689Skan#    define __INTERWORKING__
107169689Skan#   endif /* __THUMB__ || __THUMB_INTERWORK__ */
108169689Skan
109169689Skan/* Include thumb stub before arm mode code.  */
110169689Skan#  if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
111169689Skan#   define __INTERWORKING_STUBS__
112169689Skan#  endif /* __thumb__ && !__THUMB_INTERWORK__ */
113169689Skan
114169689Skan#endif /* __ARM_ARCH == 4 */
115169689Skan
116132718Skan#else
117132718Skan
118132718Skan# define RET		mov	pc, lr
119132718Skan# define RETc(x)	mov##x	pc, lr
120132718Skan
121132718Skan#endif
122132718Skan
123169689Skan.macro	cfi_pop		advance, reg, cfa_offset
124169689Skan#ifdef __ELF__
125169689Skan	.pushsection	.debug_frame
126169689Skan	.byte	0x4		/* DW_CFA_advance_loc4 */
127169689Skan	.4byte	\advance
128169689Skan	.byte	(0xc0 | \reg)	/* DW_CFA_restore */
129169689Skan	.byte	0xe		/* DW_CFA_def_cfa_offset */
130169689Skan	.uleb128 \cfa_offset
131169689Skan	.popsection
132169689Skan#endif
133169689Skan.endm
134169689Skan.macro	cfi_push	advance, reg, offset, cfa_offset
135169689Skan#ifdef __ELF__
136169689Skan	.pushsection	.debug_frame
137169689Skan	.byte	0x4		/* DW_CFA_advance_loc4 */
138169689Skan	.4byte	\advance
139169689Skan	.byte	(0x80 | \reg)	/* DW_CFA_offset */
140169689Skan	.uleb128 (\offset / -4)
141169689Skan	.byte	0xe		/* DW_CFA_def_cfa_offset */
142169689Skan	.uleb128 \cfa_offset
143169689Skan	.popsection
144169689Skan#endif
145169689Skan.endm
146169689Skan.macro cfi_start	start_label, end_label
147169689Skan#ifdef __ELF__
148169689Skan	.pushsection	.debug_frame
149169689SkanLSYM(Lstart_frame):
150169689Skan	.4byte	LSYM(Lend_cie) - LSYM(Lstart_cie) @ Length of CIE
151169689SkanLSYM(Lstart_cie):
152169689Skan        .4byte	0xffffffff	@ CIE Identifier Tag
153169689Skan        .byte	0x1	@ CIE Version
154169689Skan        .ascii	"\0"	@ CIE Augmentation
155169689Skan        .uleb128 0x1	@ CIE Code Alignment Factor
156169689Skan        .sleb128 -4	@ CIE Data Alignment Factor
157169689Skan        .byte	0xe	@ CIE RA Column
158169689Skan        .byte	0xc	@ DW_CFA_def_cfa
159169689Skan        .uleb128 0xd
160169689Skan        .uleb128 0x0
161169689Skan
162169689Skan	.align 2
163169689SkanLSYM(Lend_cie):
164169689Skan	.4byte	LSYM(Lend_fde)-LSYM(Lstart_fde)	@ FDE Length
165169689SkanLSYM(Lstart_fde):
166169689Skan	.4byte	LSYM(Lstart_frame)	@ FDE CIE offset
167169689Skan	.4byte	\start_label	@ FDE initial location
168169689Skan	.4byte	\end_label-\start_label	@ FDE address range
169169689Skan	.popsection
170169689Skan#endif
171169689Skan.endm
172169689Skan.macro cfi_end	end_label
173169689Skan#ifdef __ELF__
174169689Skan	.pushsection	.debug_frame
175169689Skan	.align	2
176169689SkanLSYM(Lend_fde):
177169689Skan	.popsection
178169689Skan\end_label:
179169689Skan#endif
180169689Skan.endm
181169689Skan
182132718Skan/* Don't pass dirn, it's there just to get token pasting right.  */
183132718Skan
184169689Skan.macro	RETLDM	regs=, cond=, unwind=, dirn=ia
185169689Skan#if defined (__INTERWORKING__)
186132718Skan	.ifc "\regs",""
187169689Skan	ldr\cond	lr, [sp], #8
188132718Skan	.else
189132718Skan	ldm\cond\dirn	sp!, {\regs, lr}
190132718Skan	.endif
191169689Skan	.ifnc "\unwind", ""
192169689Skan	/* Mark LR as restored.  */
193169689Skan97:	cfi_pop 97b - \unwind, 0xe, 0x0
194169689Skan	.endif
195132718Skan	bx\cond	lr
196132718Skan#else
197132718Skan	.ifc "\regs",""
198169689Skan	ldr\cond	pc, [sp], #8
199132718Skan	.else
200132718Skan	ldm\cond\dirn	sp!, {\regs, pc}
201132718Skan	.endif
202132718Skan#endif
203132718Skan.endm
204132718Skan
205132718Skan
206169689Skan.macro ARM_LDIV0 name
207169689Skan	str	lr, [sp, #-8]!
208169689Skan98:	cfi_push 98b - __\name, 0xe, -0x8, 0x8
20990075Sobrien	bl	SYM (__div0) __PLT__
21090075Sobrien	mov	r0, #0			@ About as wrong as it could be.
211169689Skan	RETLDM	unwind=98b
21290075Sobrien.endm
213132718Skan
214132718Skan
215169689Skan.macro THUMB_LDIV0 name
216169689Skan	push	{ r1, lr }
217169689Skan98:	cfi_push 98b - __\name, 0xe, -0x4, 0x8
21890075Sobrien	bl	SYM (__div0)
21990075Sobrien	mov	r0, #0			@ About as wrong as it could be.
220132718Skan#if defined (__INTERWORKING__)
221169689Skan	pop	{ r1, r2 }
222169689Skan	bx	r2
223132718Skan#else
224169689Skan	pop	{ r1, pc }
225132718Skan#endif
22690075Sobrien.endm
22790075Sobrien
22890075Sobrien.macro FUNC_END name
229132718Skan	SIZE (__\name)
230132718Skan.endm
231132718Skan
232132718Skan.macro DIV_FUNC_END name
233169689Skan	cfi_start	__\name, LSYM(Lend_div0)
234132718SkanLSYM(Ldiv0):
23590075Sobrien#ifdef __thumb__
236169689Skan	THUMB_LDIV0 \name
23790075Sobrien#else
238169689Skan	ARM_LDIV0 \name
23990075Sobrien#endif
240169689Skan	cfi_end	LSYM(Lend_div0)
241132718Skan	FUNC_END \name
24290075Sobrien.endm
24390075Sobrien
24490075Sobrien.macro THUMB_FUNC_START name
24590075Sobrien	.globl	SYM (\name)
24690075Sobrien	TYPE	(\name)
24790075Sobrien	.thumb_func
24890075SobrienSYM (\name):
24990075Sobrien.endm
25090075Sobrien
25190075Sobrien/* Function start macros.  Variants for ARM and Thumb.  */
25290075Sobrien
25390075Sobrien#ifdef __thumb__
25490075Sobrien#define THUMB_FUNC .thumb_func
25590075Sobrien#define THUMB_CODE .force_thumb
25690075Sobrien#else
25790075Sobrien#define THUMB_FUNC
25890075Sobrien#define THUMB_CODE
25990075Sobrien#endif
26090075Sobrien	
26190075Sobrien.macro FUNC_START name
26290075Sobrien	.text
26390075Sobrien	.globl SYM (__\name)
26490075Sobrien	TYPE (__\name)
26590075Sobrien	.align 0
26690075Sobrien	THUMB_CODE
26790075Sobrien	THUMB_FUNC
26890075SobrienSYM (__\name):
26990075Sobrien.endm
270132718Skan
271132718Skan/* Special function that will always be coded in ARM assembly, even if
272132718Skan   in Thumb-only compilation.  */
273132718Skan
274169689Skan#if defined(__INTERWORKING_STUBS__)
275132718Skan.macro	ARM_FUNC_START name
276132718Skan	FUNC_START \name
277132718Skan	bx	pc
278132718Skan	nop
279132718Skan	.arm
280169689Skan/* A hook to tell gdb that we've switched to ARM mode.  Also used to call
281169689Skan   directly from other local arm routines.  */
282169689Skan_L__\name:		
283132718Skan.endm
284132718Skan#define EQUIV .thumb_set
285169689Skan/* Branch directly to a function declared with ARM_FUNC_START.
286169689Skan   Must be called in arm mode.  */
287169689Skan.macro  ARM_CALL name
288169689Skan	bl	_L__\name
289169689Skan.endm
290132718Skan#else
291132718Skan.macro	ARM_FUNC_START name
292132718Skan	.text
293132718Skan	.globl SYM (__\name)
294132718Skan	TYPE (__\name)
295132718Skan	.align 0
296132718Skan	.arm
297132718SkanSYM (__\name):
298132718Skan.endm
299132718Skan#define EQUIV .set
300169689Skan.macro  ARM_CALL name
301169689Skan	bl	__\name
302169689Skan.endm
303132718Skan#endif
304132718Skan
305169689Skan.macro	FUNC_ALIAS new old
306169689Skan	.globl	SYM (__\new)
307169689Skan#if defined (__thumb__)
308169689Skan	.thumb_set	SYM (__\new), SYM (__\old)
309169689Skan#else
310169689Skan	.set	SYM (__\new), SYM (__\old)
311169689Skan#endif
312169689Skan.endm
313169689Skan
314132718Skan.macro	ARM_FUNC_ALIAS new old
315132718Skan	.globl	SYM (__\new)
316132718Skan	EQUIV	SYM (__\new), SYM (__\old)
317169689Skan#if defined(__INTERWORKING_STUBS__)
318169689Skan	.set	SYM (_L__\new), SYM (_L__\old)
319169689Skan#endif
320132718Skan.endm
321132718Skan
322132718Skan#ifdef __thumb__
32390075Sobrien/* Register aliases.  */
32490075Sobrien
32590075Sobrienwork		.req	r4	@ XXXX is this safe ?
32690075Sobriendividend	.req	r0
32790075Sobriendivisor		.req	r1
32890075Sobrienoverdone	.req	r2
32990075Sobrienresult		.req	r2
33090075Sobriencurbit		.req	r3
331132718Skan#endif
332132718Skan#if 0
33390075Sobrienip		.req	r12
33490075Sobriensp		.req	r13
33590075Sobrienlr		.req	r14
33690075Sobrienpc		.req	r15
337132718Skan#endif
33890075Sobrien
33990075Sobrien/* ------------------------------------------------------------------------ */
340132718Skan/*		Bodies of the division and modulo routines.		    */
34190075Sobrien/* ------------------------------------------------------------------------ */	
342132718Skan.macro ARM_DIV_BODY dividend, divisor, result, curbit
343132718Skan
344169689Skan#if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__)
345169689Skan
346169689Skan	clz	\curbit, \dividend
347169689Skan	clz	\result, \divisor
348169689Skan	sub	\curbit, \result, \curbit
349169689Skan	rsbs	\curbit, \curbit, #31
350169689Skan	addne	\curbit, \curbit, \curbit, lsl #1
351169689Skan	mov	\result, #0
352169689Skan	addne	pc, pc, \curbit, lsl #2
353169689Skan	nop
354169689Skan	.set	shift, 32
355169689Skan	.rept	32
356169689Skan	.set	shift, shift - 1
357169689Skan	cmp	\dividend, \divisor, lsl #shift
358169689Skan	adc	\result, \result, \result
359169689Skan	subcs	\dividend, \dividend, \divisor, lsl #shift
360169689Skan	.endr
361169689Skan
362169689Skan#else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */
363132718Skan#if __ARM_ARCH__ >= 5
364132718Skan
365132718Skan	clz	\curbit, \divisor
366132718Skan	clz	\result, \dividend
367132718Skan	sub	\result, \curbit, \result
368132718Skan	mov	\curbit, #1
369132718Skan	mov	\divisor, \divisor, lsl \result
370132718Skan	mov	\curbit, \curbit, lsl \result
371132718Skan	mov	\result, #0
372132718Skan	
373169689Skan#else /* __ARM_ARCH__ < 5 */
374132718Skan
375132718Skan	@ Initially shift the divisor left 3 bits if possible,
376132718Skan	@ set curbit accordingly.  This allows for curbit to be located
377132718Skan	@ at the left end of each 4 bit nibbles in the division loop
378132718Skan	@ to save one loop in most cases.
379132718Skan	tst	\divisor, #0xe0000000
380132718Skan	moveq	\divisor, \divisor, lsl #3
381132718Skan	moveq	\curbit, #8
382132718Skan	movne	\curbit, #1
383132718Skan
38490075Sobrien	@ Unless the divisor is very big, shift it up in multiples of
38590075Sobrien	@ four bits, since this is the amount of unwinding in the main
38690075Sobrien	@ division loop.  Continue shifting until the divisor is 
38790075Sobrien	@ larger than the dividend.
388132718Skan1:	cmp	\divisor, #0x10000000
389132718Skan	cmplo	\divisor, \dividend
390132718Skan	movlo	\divisor, \divisor, lsl #4
391132718Skan	movlo	\curbit, \curbit, lsl #4
392132718Skan	blo	1b
39390075Sobrien
39490075Sobrien	@ For very big divisors, we must shift it a bit at a time, or
39590075Sobrien	@ we will be in danger of overflowing.
396132718Skan1:	cmp	\divisor, #0x80000000
397132718Skan	cmplo	\divisor, \dividend
398132718Skan	movlo	\divisor, \divisor, lsl #1
399132718Skan	movlo	\curbit, \curbit, lsl #1
400132718Skan	blo	1b
40190075Sobrien
402132718Skan	mov	\result, #0
403132718Skan
404169689Skan#endif /* __ARM_ARCH__ < 5 */
405132718Skan
406132718Skan	@ Division loop
407132718Skan1:	cmp	\dividend, \divisor
408132718Skan	subhs	\dividend, \dividend, \divisor
409132718Skan	orrhs	\result,   \result,   \curbit
410132718Skan	cmp	\dividend, \divisor,  lsr #1
411132718Skan	subhs	\dividend, \dividend, \divisor, lsr #1
412132718Skan	orrhs	\result,   \result,   \curbit,  lsr #1
413132718Skan	cmp	\dividend, \divisor,  lsr #2
414132718Skan	subhs	\dividend, \dividend, \divisor, lsr #2
415132718Skan	orrhs	\result,   \result,   \curbit,  lsr #2
416132718Skan	cmp	\dividend, \divisor,  lsr #3
417132718Skan	subhs	\dividend, \dividend, \divisor, lsr #3
418132718Skan	orrhs	\result,   \result,   \curbit,  lsr #3
419132718Skan	cmp	\dividend, #0			@ Early termination?
420132718Skan	movnes	\curbit,   \curbit,  lsr #4	@ No, any more bits to do?
421132718Skan	movne	\divisor,  \divisor, lsr #4
422132718Skan	bne	1b
423132718Skan
424169689Skan#endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */
425169689Skan
426132718Skan.endm
427132718Skan/* ------------------------------------------------------------------------ */	
428132718Skan.macro ARM_DIV2_ORDER divisor, order
429132718Skan
430132718Skan#if __ARM_ARCH__ >= 5
431132718Skan
432132718Skan	clz	\order, \divisor
433132718Skan	rsb	\order, \order, #31
434132718Skan
435132718Skan#else
436132718Skan
437132718Skan	cmp	\divisor, #(1 << 16)
438132718Skan	movhs	\divisor, \divisor, lsr #16
439132718Skan	movhs	\order, #16
440132718Skan	movlo	\order, #0
441132718Skan
442132718Skan	cmp	\divisor, #(1 << 8)
443132718Skan	movhs	\divisor, \divisor, lsr #8
444132718Skan	addhs	\order, \order, #8
445132718Skan
446132718Skan	cmp	\divisor, #(1 << 4)
447132718Skan	movhs	\divisor, \divisor, lsr #4
448132718Skan	addhs	\order, \order, #4
449132718Skan
450132718Skan	cmp	\divisor, #(1 << 2)
451132718Skan	addhi	\order, \order, #3
452132718Skan	addls	\order, \order, \divisor, lsr #1
453132718Skan
454132718Skan#endif
455132718Skan
456132718Skan.endm
457132718Skan/* ------------------------------------------------------------------------ */
458132718Skan.macro ARM_MOD_BODY dividend, divisor, order, spare
459132718Skan
460169689Skan#if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__)
461169689Skan
462169689Skan	clz	\order, \divisor
463169689Skan	clz	\spare, \dividend
464169689Skan	sub	\order, \order, \spare
465169689Skan	rsbs	\order, \order, #31
466169689Skan	addne	pc, pc, \order, lsl #3
467169689Skan	nop
468169689Skan	.set	shift, 32
469169689Skan	.rept	32
470169689Skan	.set	shift, shift - 1
471169689Skan	cmp	\dividend, \divisor, lsl #shift
472169689Skan	subcs	\dividend, \dividend, \divisor, lsl #shift
473169689Skan	.endr
474169689Skan
475169689Skan#else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */
476132718Skan#if __ARM_ARCH__ >= 5
477132718Skan
478132718Skan	clz	\order, \divisor
479132718Skan	clz	\spare, \dividend
480132718Skan	sub	\order, \order, \spare
481132718Skan	mov	\divisor, \divisor, lsl \order
48290075Sobrien	
483169689Skan#else /* __ARM_ARCH__ < 5 */
48490075Sobrien
485132718Skan	mov	\order, #0
48690075Sobrien
487132718Skan	@ Unless the divisor is very big, shift it up in multiples of
488132718Skan	@ four bits, since this is the amount of unwinding in the main
489132718Skan	@ division loop.  Continue shifting until the divisor is 
490132718Skan	@ larger than the dividend.
491132718Skan1:	cmp	\divisor, #0x10000000
492132718Skan	cmplo	\divisor, \dividend
493132718Skan	movlo	\divisor, \divisor, lsl #4
494132718Skan	addlo	\order, \order, #4
495132718Skan	blo	1b
49690075Sobrien
497132718Skan	@ For very big divisors, we must shift it a bit at a time, or
498132718Skan	@ we will be in danger of overflowing.
499132718Skan1:	cmp	\divisor, #0x80000000
500132718Skan	cmplo	\divisor, \dividend
501132718Skan	movlo	\divisor, \divisor, lsl #1
502132718Skan	addlo	\order, \order, #1
503132718Skan	blo	1b
504132718Skan
505169689Skan#endif /* __ARM_ARCH__ < 5 */
506132718Skan
507132718Skan	@ Perform all needed substractions to keep only the reminder.
508132718Skan	@ Do comparisons in batch of 4 first.
509132718Skan	subs	\order, \order, #3		@ yes, 3 is intended here
510132718Skan	blt	2f
511132718Skan
512132718Skan1:	cmp	\dividend, \divisor
513132718Skan	subhs	\dividend, \dividend, \divisor
514132718Skan	cmp	\dividend, \divisor,  lsr #1
515132718Skan	subhs	\dividend, \dividend, \divisor, lsr #1
516132718Skan	cmp	\dividend, \divisor,  lsr #2
517132718Skan	subhs	\dividend, \dividend, \divisor, lsr #2
518132718Skan	cmp	\dividend, \divisor,  lsr #3
519132718Skan	subhs	\dividend, \dividend, \divisor, lsr #3
520132718Skan	cmp	\dividend, #1
521132718Skan	mov	\divisor, \divisor, lsr #4
522132718Skan	subges	\order, \order, #4
523132718Skan	bge	1b
524132718Skan
525132718Skan	tst	\order, #3
526132718Skan	teqne	\dividend, #0
527132718Skan	beq	5f
528132718Skan
529132718Skan	@ Either 1, 2 or 3 comparison/substractions are left.
530132718Skan2:	cmn	\order, #2
531132718Skan	blt	4f
532132718Skan	beq	3f
533132718Skan	cmp	\dividend, \divisor
534132718Skan	subhs	\dividend, \dividend, \divisor
535132718Skan	mov	\divisor,  \divisor,  lsr #1
536132718Skan3:	cmp	\dividend, \divisor
537132718Skan	subhs	\dividend, \dividend, \divisor
538132718Skan	mov	\divisor,  \divisor,  lsr #1
539132718Skan4:	cmp	\dividend, \divisor
540132718Skan	subhs	\dividend, \dividend, \divisor
541132718Skan5:
542169689Skan
543169689Skan#endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */
544169689Skan
54590075Sobrien.endm
54690075Sobrien/* ------------------------------------------------------------------------ */
54790075Sobrien.macro THUMB_DIV_MOD_BODY modulo
54890075Sobrien	@ Load the constant 0x10000000 into our work register.
54990075Sobrien	mov	work, #1
55090075Sobrien	lsl	work, #28
551132718SkanLSYM(Loop1):
55290075Sobrien	@ Unless the divisor is very big, shift it up in multiples of
55390075Sobrien	@ four bits, since this is the amount of unwinding in the main
55490075Sobrien	@ division loop.  Continue shifting until the divisor is 
55590075Sobrien	@ larger than the dividend.
55690075Sobrien	cmp	divisor, work
557132718Skan	bhs	LSYM(Lbignum)
55890075Sobrien	cmp	divisor, dividend
559132718Skan	bhs	LSYM(Lbignum)
56090075Sobrien	lsl	divisor, #4
56190075Sobrien	lsl	curbit,  #4
562132718Skan	b	LSYM(Loop1)
563132718SkanLSYM(Lbignum):
56490075Sobrien	@ Set work to 0x80000000
56590075Sobrien	lsl	work, #3
566132718SkanLSYM(Loop2):
56790075Sobrien	@ For very big divisors, we must shift it a bit at a time, or
56890075Sobrien	@ we will be in danger of overflowing.
56990075Sobrien	cmp	divisor, work
570132718Skan	bhs	LSYM(Loop3)
57190075Sobrien	cmp	divisor, dividend
572132718Skan	bhs	LSYM(Loop3)
57390075Sobrien	lsl	divisor, #1
57490075Sobrien	lsl	curbit,  #1
575132718Skan	b	LSYM(Loop2)
576132718SkanLSYM(Loop3):
57790075Sobrien	@ Test for possible subtractions ...
57890075Sobrien  .if \modulo
57990075Sobrien	@ ... On the final pass, this may subtract too much from the dividend, 
58090075Sobrien	@ so keep track of which subtractions are done, we can fix them up 
58190075Sobrien	@ afterwards.
58290075Sobrien	mov	overdone, #0
58390075Sobrien	cmp	dividend, divisor
584132718Skan	blo	LSYM(Lover1)
58590075Sobrien	sub	dividend, dividend, divisor
586132718SkanLSYM(Lover1):
58790075Sobrien	lsr	work, divisor, #1
58890075Sobrien	cmp	dividend, work
589132718Skan	blo	LSYM(Lover2)
59090075Sobrien	sub	dividend, dividend, work
59190075Sobrien	mov	ip, curbit
59290075Sobrien	mov	work, #1
59390075Sobrien	ror	curbit, work
59490075Sobrien	orr	overdone, curbit
59590075Sobrien	mov	curbit, ip
596132718SkanLSYM(Lover2):
59790075Sobrien	lsr	work, divisor, #2
59890075Sobrien	cmp	dividend, work
599132718Skan	blo	LSYM(Lover3)
60090075Sobrien	sub	dividend, dividend, work
60190075Sobrien	mov	ip, curbit
60290075Sobrien	mov	work, #2
60390075Sobrien	ror	curbit, work
60490075Sobrien	orr	overdone, curbit
60590075Sobrien	mov	curbit, ip
606132718SkanLSYM(Lover3):
60790075Sobrien	lsr	work, divisor, #3
60890075Sobrien	cmp	dividend, work
609132718Skan	blo	LSYM(Lover4)
61090075Sobrien	sub	dividend, dividend, work
61190075Sobrien	mov	ip, curbit
61290075Sobrien	mov	work, #3
61390075Sobrien	ror	curbit, work
61490075Sobrien	orr	overdone, curbit
61590075Sobrien	mov	curbit, ip
616132718SkanLSYM(Lover4):
61790075Sobrien	mov	ip, curbit
61890075Sobrien  .else
61990075Sobrien	@ ... and note which bits are done in the result.  On the final pass,
62090075Sobrien	@ this may subtract too much from the dividend, but the result will be ok,
62190075Sobrien	@ since the "bit" will have been shifted out at the bottom.
62290075Sobrien	cmp	dividend, divisor
623132718Skan	blo	LSYM(Lover1)
62490075Sobrien	sub	dividend, dividend, divisor
62590075Sobrien	orr	result, result, curbit
626132718SkanLSYM(Lover1):
62790075Sobrien	lsr	work, divisor, #1
62890075Sobrien	cmp	dividend, work
629132718Skan	blo	LSYM(Lover2)
63090075Sobrien	sub	dividend, dividend, work
63190075Sobrien	lsr	work, curbit, #1
63290075Sobrien	orr	result, work
633132718SkanLSYM(Lover2):
63490075Sobrien	lsr	work, divisor, #2
63590075Sobrien	cmp	dividend, work
636132718Skan	blo	LSYM(Lover3)
63790075Sobrien	sub	dividend, dividend, work
63890075Sobrien	lsr	work, curbit, #2
63990075Sobrien	orr	result, work
640132718SkanLSYM(Lover3):
64190075Sobrien	lsr	work, divisor, #3
64290075Sobrien	cmp	dividend, work
643132718Skan	blo	LSYM(Lover4)
64490075Sobrien	sub	dividend, dividend, work
64590075Sobrien	lsr	work, curbit, #3
64690075Sobrien	orr	result, work
647132718SkanLSYM(Lover4):
64890075Sobrien  .endif
64990075Sobrien	
65090075Sobrien	cmp	dividend, #0			@ Early termination?
651132718Skan	beq	LSYM(Lover5)
65290075Sobrien	lsr	curbit,  #4			@ No, any more bits to do?
653132718Skan	beq	LSYM(Lover5)
65490075Sobrien	lsr	divisor, #4
655132718Skan	b	LSYM(Loop3)
656132718SkanLSYM(Lover5):
65790075Sobrien  .if \modulo
65890075Sobrien	@ Any subtractions that we should not have done will be recorded in
65990075Sobrien	@ the top three bits of "overdone".  Exactly which were not needed
66090075Sobrien	@ are governed by the position of the bit, stored in ip.
66190075Sobrien	mov	work, #0xe
66290075Sobrien	lsl	work, #28
66390075Sobrien	and	overdone, work
664132718Skan	beq	LSYM(Lgot_result)
66590075Sobrien	
66690075Sobrien	@ If we terminated early, because dividend became zero, then the 
66790075Sobrien	@ bit in ip will not be in the bottom nibble, and we should not
66890075Sobrien	@ perform the additions below.  We must test for this though
66990075Sobrien	@ (rather relying upon the TSTs to prevent the additions) since
67090075Sobrien	@ the bit in ip could be in the top two bits which might then match
67190075Sobrien	@ with one of the smaller RORs.
67290075Sobrien	mov	curbit, ip
67390075Sobrien	mov	work, #0x7
67490075Sobrien	tst	curbit, work
675132718Skan	beq	LSYM(Lgot_result)
67690075Sobrien	
67790075Sobrien	mov	curbit, ip
67890075Sobrien	mov	work, #3
67990075Sobrien	ror	curbit, work
68090075Sobrien	tst	overdone, curbit
681132718Skan	beq	LSYM(Lover6)
68290075Sobrien	lsr	work, divisor, #3
68390075Sobrien	add	dividend, work
684132718SkanLSYM(Lover6):
68590075Sobrien	mov	curbit, ip
68690075Sobrien	mov	work, #2
68790075Sobrien	ror	curbit, work
68890075Sobrien	tst	overdone, curbit
689132718Skan	beq	LSYM(Lover7)
69090075Sobrien	lsr	work, divisor, #2
69190075Sobrien	add	dividend, work
692132718SkanLSYM(Lover7):
69390075Sobrien	mov	curbit, ip
69490075Sobrien	mov	work, #1
69590075Sobrien	ror	curbit, work
69690075Sobrien	tst	overdone, curbit
697132718Skan	beq	LSYM(Lgot_result)
69890075Sobrien	lsr	work, divisor, #1
69990075Sobrien	add	dividend, work
70090075Sobrien  .endif
701132718SkanLSYM(Lgot_result):
70290075Sobrien.endm	
70390075Sobrien/* ------------------------------------------------------------------------ */
70490075Sobrien/*		Start of the Real Functions				    */
70590075Sobrien/* ------------------------------------------------------------------------ */
70690075Sobrien#ifdef L_udivsi3
70790075Sobrien
70890075Sobrien	FUNC_START udivsi3
709169689Skan	FUNC_ALIAS aeabi_uidiv udivsi3
71090075Sobrien
71190075Sobrien#ifdef __thumb__
71290075Sobrien
71390075Sobrien	cmp	divisor, #0
714132718Skan	beq	LSYM(Ldiv0)
71590075Sobrien	mov	curbit, #1
71690075Sobrien	mov	result, #0
71790075Sobrien	
71890075Sobrien	push	{ work }
71990075Sobrien	cmp	dividend, divisor
720132718Skan	blo	LSYM(Lgot_result)
72190075Sobrien
72290075Sobrien	THUMB_DIV_MOD_BODY 0
72390075Sobrien	
72490075Sobrien	mov	r0, result
72590075Sobrien	pop	{ work }
72690075Sobrien	RET
72790075Sobrien
72890075Sobrien#else /* ARM version.  */
729132718Skan
730132718Skan	subs	r2, r1, #1
731132718Skan	RETc(eq)
732132718Skan	bcc	LSYM(Ldiv0)
733132718Skan	cmp	r0, r1
734132718Skan	bls	11f
735132718Skan	tst	r1, r2
736132718Skan	beq	12f
73790075Sobrien	
738132718Skan	ARM_DIV_BODY r0, r1, r2, r3
73990075Sobrien	
740132718Skan	mov	r0, r2
74190075Sobrien	RET	
74290075Sobrien
743132718Skan11:	moveq	r0, #1
744132718Skan	movne	r0, #0
745132718Skan	RET
746132718Skan
747132718Skan12:	ARM_DIV2_ORDER r1, r2
748132718Skan
749132718Skan	mov	r0, r0, lsr r2
750132718Skan	RET
751132718Skan
75290075Sobrien#endif /* ARM version */
75390075Sobrien
754132718Skan	DIV_FUNC_END udivsi3
75590075Sobrien
756169689SkanFUNC_START aeabi_uidivmod
757169689Skan#ifdef __thumb__
758169689Skan	push	{r0, r1, lr}
759169689Skan	bl	SYM(__udivsi3)
760169689Skan	POP	{r1, r2, r3}
761169689Skan	mul	r2, r0
762169689Skan	sub	r1, r1, r2
763169689Skan	bx	r3
764169689Skan#else
765169689Skan	stmfd	sp!, { r0, r1, lr }
766169689Skan	bl	SYM(__udivsi3)
767169689Skan	ldmfd	sp!, { r1, r2, lr }
768169689Skan	mul	r3, r2, r0
769169689Skan	sub	r1, r1, r3
770169689Skan	RET
771169689Skan#endif
772169689Skan	FUNC_END aeabi_uidivmod
773169689Skan	
77490075Sobrien#endif /* L_udivsi3 */
77590075Sobrien/* ------------------------------------------------------------------------ */
77690075Sobrien#ifdef L_umodsi3
77790075Sobrien
77890075Sobrien	FUNC_START umodsi3
77990075Sobrien
78090075Sobrien#ifdef __thumb__
78190075Sobrien
78290075Sobrien	cmp	divisor, #0
783132718Skan	beq	LSYM(Ldiv0)
78490075Sobrien	mov	curbit, #1
78590075Sobrien	cmp	dividend, divisor
786132718Skan	bhs	LSYM(Lover10)
78790075Sobrien	RET	
78890075Sobrien
789132718SkanLSYM(Lover10):
79090075Sobrien	push	{ work }
79190075Sobrien
79290075Sobrien	THUMB_DIV_MOD_BODY 1
79390075Sobrien	
79490075Sobrien	pop	{ work }
79590075Sobrien	RET
79690075Sobrien	
79790075Sobrien#else  /* ARM version.  */
79890075Sobrien	
799132718Skan	subs	r2, r1, #1			@ compare divisor with 1
800132718Skan	bcc	LSYM(Ldiv0)
801132718Skan	cmpne	r0, r1				@ compare dividend with divisor
802132718Skan	moveq   r0, #0
803132718Skan	tsthi	r1, r2				@ see if divisor is power of 2
804132718Skan	andeq	r0, r0, r2
805132718Skan	RETc(ls)
80690075Sobrien
807132718Skan	ARM_MOD_BODY r0, r1, r2, r3
80890075Sobrien	
80990075Sobrien	RET	
81090075Sobrien
81190075Sobrien#endif /* ARM version.  */
81290075Sobrien	
813132718Skan	DIV_FUNC_END umodsi3
81490075Sobrien
81590075Sobrien#endif /* L_umodsi3 */
81690075Sobrien/* ------------------------------------------------------------------------ */
81790075Sobrien#ifdef L_divsi3
81890075Sobrien
81990075Sobrien	FUNC_START divsi3	
820169689Skan	FUNC_ALIAS aeabi_idiv divsi3
82190075Sobrien
82290075Sobrien#ifdef __thumb__
82390075Sobrien	cmp	divisor, #0
824132718Skan	beq	LSYM(Ldiv0)
82590075Sobrien	
82690075Sobrien	push	{ work }
82790075Sobrien	mov	work, dividend
82890075Sobrien	eor	work, divisor		@ Save the sign of the result.
82990075Sobrien	mov	ip, work
83090075Sobrien	mov	curbit, #1
83190075Sobrien	mov	result, #0
83290075Sobrien	cmp	divisor, #0
833132718Skan	bpl	LSYM(Lover10)
83490075Sobrien	neg	divisor, divisor	@ Loops below use unsigned.
835132718SkanLSYM(Lover10):
83690075Sobrien	cmp	dividend, #0
837132718Skan	bpl	LSYM(Lover11)
83890075Sobrien	neg	dividend, dividend
839132718SkanLSYM(Lover11):
84090075Sobrien	cmp	dividend, divisor
841132718Skan	blo	LSYM(Lgot_result)
84290075Sobrien
84390075Sobrien	THUMB_DIV_MOD_BODY 0
84490075Sobrien	
84590075Sobrien	mov	r0, result
84690075Sobrien	mov	work, ip
84790075Sobrien	cmp	work, #0
848132718Skan	bpl	LSYM(Lover12)
84990075Sobrien	neg	r0, r0
850132718SkanLSYM(Lover12):
85190075Sobrien	pop	{ work }
85290075Sobrien	RET
85390075Sobrien
85490075Sobrien#else /* ARM version.  */
85590075Sobrien	
856132718Skan	cmp	r1, #0
857132718Skan	eor	ip, r0, r1			@ save the sign of the result.
858132718Skan	beq	LSYM(Ldiv0)
859132718Skan	rsbmi	r1, r1, #0			@ loops below use unsigned.
860132718Skan	subs	r2, r1, #1			@ division by 1 or -1 ?
861132718Skan	beq	10f
862132718Skan	movs	r3, r0
863132718Skan	rsbmi	r3, r0, #0			@ positive dividend value
864132718Skan	cmp	r3, r1
865132718Skan	bls	11f
866132718Skan	tst	r1, r2				@ divisor is power of 2 ?
867132718Skan	beq	12f
86890075Sobrien
869132718Skan	ARM_DIV_BODY r3, r1, r0, r2
87090075Sobrien	
87190075Sobrien	cmp	ip, #0
87290075Sobrien	rsbmi	r0, r0, #0
87390075Sobrien	RET	
87490075Sobrien
875132718Skan10:	teq	ip, r0				@ same sign ?
876132718Skan	rsbmi	r0, r0, #0
877132718Skan	RET	
878132718Skan
879132718Skan11:	movlo	r0, #0
880132718Skan	moveq	r0, ip, asr #31
881132718Skan	orreq	r0, r0, #1
882132718Skan	RET
883132718Skan
884132718Skan12:	ARM_DIV2_ORDER r1, r2
885132718Skan
886132718Skan	cmp	ip, #0
887132718Skan	mov	r0, r3, lsr r2
888132718Skan	rsbmi	r0, r0, #0
889132718Skan	RET
890132718Skan
89190075Sobrien#endif /* ARM version */
89290075Sobrien	
893132718Skan	DIV_FUNC_END divsi3
89490075Sobrien
895169689SkanFUNC_START aeabi_idivmod
896169689Skan#ifdef __thumb__
897169689Skan	push	{r0, r1, lr}
898169689Skan	bl	SYM(__divsi3)
899169689Skan	POP	{r1, r2, r3}
900169689Skan	mul	r2, r0
901169689Skan	sub	r1, r1, r2
902169689Skan	bx	r3
903169689Skan#else
904169689Skan	stmfd	sp!, { r0, r1, lr }
905169689Skan	bl	SYM(__divsi3)
906169689Skan	ldmfd	sp!, { r1, r2, lr }
907169689Skan	mul	r3, r2, r0
908169689Skan	sub	r1, r1, r3
909169689Skan	RET
910169689Skan#endif
911169689Skan	FUNC_END aeabi_idivmod
912169689Skan	
91390075Sobrien#endif /* L_divsi3 */
91490075Sobrien/* ------------------------------------------------------------------------ */
91590075Sobrien#ifdef L_modsi3
91690075Sobrien
91790075Sobrien	FUNC_START modsi3
91890075Sobrien
91990075Sobrien#ifdef __thumb__
92090075Sobrien
92190075Sobrien	mov	curbit, #1
92290075Sobrien	cmp	divisor, #0
923132718Skan	beq	LSYM(Ldiv0)
924132718Skan	bpl	LSYM(Lover10)
92590075Sobrien	neg	divisor, divisor		@ Loops below use unsigned.
926132718SkanLSYM(Lover10):
92790075Sobrien	push	{ work }
92890075Sobrien	@ Need to save the sign of the dividend, unfortunately, we need
92990075Sobrien	@ work later on.  Must do this after saving the original value of
93090075Sobrien	@ the work register, because we will pop this value off first.
93190075Sobrien	push	{ dividend }
93290075Sobrien	cmp	dividend, #0
933132718Skan	bpl	LSYM(Lover11)
93490075Sobrien	neg	dividend, dividend
935132718SkanLSYM(Lover11):
93690075Sobrien	cmp	dividend, divisor
937132718Skan	blo	LSYM(Lgot_result)
93890075Sobrien
93990075Sobrien	THUMB_DIV_MOD_BODY 1
94090075Sobrien		
94190075Sobrien	pop	{ work }
94290075Sobrien	cmp	work, #0
943132718Skan	bpl	LSYM(Lover12)
94490075Sobrien	neg	dividend, dividend
945132718SkanLSYM(Lover12):
94690075Sobrien	pop	{ work }
94790075Sobrien	RET	
94890075Sobrien
94990075Sobrien#else /* ARM version.  */
95090075Sobrien	
951132718Skan	cmp	r1, #0
952132718Skan	beq	LSYM(Ldiv0)
953132718Skan	rsbmi	r1, r1, #0			@ loops below use unsigned.
954132718Skan	movs	ip, r0				@ preserve sign of dividend
955132718Skan	rsbmi	r0, r0, #0			@ if negative make positive
956132718Skan	subs	r2, r1, #1			@ compare divisor with 1
957132718Skan	cmpne	r0, r1				@ compare dividend with divisor
958132718Skan	moveq	r0, #0
959132718Skan	tsthi	r1, r2				@ see if divisor is power of 2
960132718Skan	andeq	r0, r0, r2
961132718Skan	bls	10f
96290075Sobrien
963132718Skan	ARM_MOD_BODY r0, r1, r2, r3
96490075Sobrien
965132718Skan10:	cmp	ip, #0
966132718Skan	rsbmi	r0, r0, #0
96790075Sobrien	RET	
96890075Sobrien
96990075Sobrien#endif /* ARM version */
97090075Sobrien	
971132718Skan	DIV_FUNC_END modsi3
97290075Sobrien
97390075Sobrien#endif /* L_modsi3 */
97490075Sobrien/* ------------------------------------------------------------------------ */
97590075Sobrien#ifdef L_dvmd_tls
97690075Sobrien
97790075Sobrien	FUNC_START div0
978169689Skan	FUNC_ALIAS aeabi_idiv0 div0
979169689Skan	FUNC_ALIAS aeabi_ldiv0 div0
98090075Sobrien
98190075Sobrien	RET
98290075Sobrien
983132718Skan	FUNC_END div0
98490075Sobrien	
98590075Sobrien#endif /* L_divmodsi_tools */
98690075Sobrien/* ------------------------------------------------------------------------ */
98790075Sobrien#ifdef L_dvmd_lnx
98890075Sobrien@ GNU/Linux division-by zero handler.  Used in place of L_dvmd_tls
98990075Sobrien
990169689Skan/* Constant taken from <asm/signal.h>.  */
99190075Sobrien#define SIGFPE	8
99290075Sobrien
993132718Skan	.code	32
99490075Sobrien	FUNC_START div0
99590075Sobrien
99690075Sobrien	stmfd	sp!, {r1, lr}
997169689Skan	mov	r0, #SIGFPE
998169689Skan	bl	SYM(raise) __PLT__
999132718Skan	RETLDM	r1
100090075Sobrien
1001132718Skan	FUNC_END div0
100290075Sobrien	
100390075Sobrien#endif /* L_dvmd_lnx */
100490075Sobrien/* ------------------------------------------------------------------------ */
1005169689Skan/* Dword shift operations.  */
1006169689Skan/* All the following Dword shift variants rely on the fact that
1007169689Skan	shft xxx, Reg
1008169689Skan   is in fact done as
1009169689Skan	shft xxx, (Reg & 255)
1010169689Skan   so for Reg value in (32...63) and (-1...-31) we will get zero (in the
1011169689Skan   case of logical shifts) or the sign (for asr).  */
1012169689Skan
1013169689Skan#ifdef __ARMEB__
1014169689Skan#define al	r1
1015169689Skan#define ah	r0
1016169689Skan#else
1017169689Skan#define al	r0
1018169689Skan#define ah	r1
1019169689Skan#endif
1020169689Skan
1021169689Skan/* Prevent __aeabi double-word shifts from being produced on SymbianOS.  */
1022169689Skan#ifndef __symbian__
1023169689Skan
1024169689Skan#ifdef L_lshrdi3
1025169689Skan
1026169689Skan	FUNC_START lshrdi3
1027169689Skan	FUNC_ALIAS aeabi_llsr lshrdi3
1028169689Skan	
1029169689Skan#ifdef __thumb__
1030169689Skan	lsr	al, r2
1031169689Skan	mov	r3, ah
1032169689Skan	lsr	ah, r2
1033169689Skan	mov	ip, r3
1034169689Skan	sub	r2, #32
1035169689Skan	lsr	r3, r2
1036169689Skan	orr	al, r3
1037169689Skan	neg	r2, r2
1038169689Skan	mov	r3, ip
1039169689Skan	lsl	r3, r2
1040169689Skan	orr	al, r3
1041169689Skan	RET
1042169689Skan#else
1043169689Skan	subs	r3, r2, #32
1044169689Skan	rsb	ip, r2, #32
1045169689Skan	movmi	al, al, lsr r2
1046169689Skan	movpl	al, ah, lsr r3
1047169689Skan	orrmi	al, al, ah, lsl ip
1048169689Skan	mov	ah, ah, lsr r2
1049169689Skan	RET
1050169689Skan#endif
1051169689Skan	FUNC_END aeabi_llsr
1052169689Skan	FUNC_END lshrdi3
1053169689Skan
1054169689Skan#endif
1055169689Skan	
1056169689Skan#ifdef L_ashrdi3
1057169689Skan	
1058169689Skan	FUNC_START ashrdi3
1059169689Skan	FUNC_ALIAS aeabi_lasr ashrdi3
1060169689Skan	
1061169689Skan#ifdef __thumb__
1062169689Skan	lsr	al, r2
1063169689Skan	mov	r3, ah
1064169689Skan	asr	ah, r2
1065169689Skan	sub	r2, #32
1066169689Skan	@ If r2 is negative at this point the following step would OR
1067169689Skan	@ the sign bit into all of AL.  That's not what we want...
1068169689Skan	bmi	1f
1069169689Skan	mov	ip, r3
1070169689Skan	asr	r3, r2
1071169689Skan	orr	al, r3
1072169689Skan	mov	r3, ip
1073169689Skan1:
1074169689Skan	neg	r2, r2
1075169689Skan	lsl	r3, r2
1076169689Skan	orr	al, r3
1077169689Skan	RET
1078169689Skan#else
1079169689Skan	subs	r3, r2, #32
1080169689Skan	rsb	ip, r2, #32
1081169689Skan	movmi	al, al, lsr r2
1082169689Skan	movpl	al, ah, asr r3
1083169689Skan	orrmi	al, al, ah, lsl ip
1084169689Skan	mov	ah, ah, asr r2
1085169689Skan	RET
1086169689Skan#endif
1087169689Skan
1088169689Skan	FUNC_END aeabi_lasr
1089169689Skan	FUNC_END ashrdi3
1090169689Skan
1091169689Skan#endif
1092169689Skan
1093169689Skan#ifdef L_ashldi3
1094169689Skan
1095169689Skan	FUNC_START ashldi3
1096169689Skan	FUNC_ALIAS aeabi_llsl ashldi3
1097169689Skan	
1098169689Skan#ifdef __thumb__
1099169689Skan	lsl	ah, r2
1100169689Skan	mov	r3, al
1101169689Skan	lsl	al, r2
1102169689Skan	mov	ip, r3
1103169689Skan	sub	r2, #32
1104169689Skan	lsl	r3, r2
1105169689Skan	orr	ah, r3
1106169689Skan	neg	r2, r2
1107169689Skan	mov	r3, ip
1108169689Skan	lsr	r3, r2
1109169689Skan	orr	ah, r3
1110169689Skan	RET
1111169689Skan#else
1112169689Skan	subs	r3, r2, #32
1113169689Skan	rsb	ip, r2, #32
1114169689Skan	movmi	ah, ah, lsl r2
1115169689Skan	movpl	ah, al, lsl r3
1116169689Skan	orrmi	ah, ah, al, lsr ip
1117169689Skan	mov	al, al, lsl r2
1118169689Skan	RET
1119169689Skan#endif
1120169689Skan	FUNC_END aeabi_llsl
1121169689Skan	FUNC_END ashldi3
1122169689Skan
1123169689Skan#endif
1124169689Skan
1125169689Skan#endif /* __symbian__ */
1126169689Skan
1127169689Skan/* ------------------------------------------------------------------------ */
112890075Sobrien/* These next two sections are here despite the fact that they contain Thumb 
112990075Sobrien   assembler because their presence allows interworked code to be linked even
113090075Sobrien   when the GCC library is this one.  */
113190075Sobrien		
113290075Sobrien/* Do not build the interworking functions when the target architecture does 
113390075Sobrien   not support Thumb instructions.  (This can be a multilib option).  */
1134169689Skan#if defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__\
1135169689Skan      || defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ \
1136169689Skan      || __ARM_ARCH__ >= 6
113790075Sobrien
1138169689Skan#if defined L_call_via_rX
1139169689Skan
114090075Sobrien/* These labels & instructions are used by the Arm/Thumb interworking code. 
114190075Sobrien   The address of function to be called is loaded into a register and then 
114290075Sobrien   one of these labels is called via a BL instruction.  This puts the 
114390075Sobrien   return address into the link register with the bottom bit set, and the 
114490075Sobrien   code here switches to the correct mode before executing the function.  */
114590075Sobrien	
114690075Sobrien	.text
114790075Sobrien	.align 0
114890075Sobrien        .force_thumb
114990075Sobrien
115090075Sobrien.macro call_via register
115190075Sobrien	THUMB_FUNC_START _call_via_\register
115290075Sobrien
115390075Sobrien	bx	\register
115490075Sobrien	nop
115590075Sobrien
115690075Sobrien	SIZE	(_call_via_\register)
115790075Sobrien.endm
115890075Sobrien
115990075Sobrien	call_via r0
116090075Sobrien	call_via r1
116190075Sobrien	call_via r2
116290075Sobrien	call_via r3
116390075Sobrien	call_via r4
116490075Sobrien	call_via r5
116590075Sobrien	call_via r6
116690075Sobrien	call_via r7
116790075Sobrien	call_via r8
116890075Sobrien	call_via r9
116990075Sobrien	call_via sl
117090075Sobrien	call_via fp
117190075Sobrien	call_via ip
117290075Sobrien	call_via sp
117390075Sobrien	call_via lr
117490075Sobrien
117590075Sobrien#endif /* L_call_via_rX */
117690075Sobrien
1177169689Skan#if defined L_interwork_call_via_rX
1178169689Skan
117990075Sobrien/* These labels & instructions are used by the Arm/Thumb interworking code,
118090075Sobrien   when the target address is in an unknown instruction set.  The address 
118190075Sobrien   of function to be called is loaded into a register and then one of these
118290075Sobrien   labels is called via a BL instruction.  This puts the return address 
118390075Sobrien   into the link register with the bottom bit set, and the code here 
118490075Sobrien   switches to the correct mode before executing the function.  Unfortunately
118590075Sobrien   the target code cannot be relied upon to return via a BX instruction, so
118690075Sobrien   instead we have to store the resturn address on the stack and allow the
118790075Sobrien   called function to return here instead.  Upon return we recover the real
1188169689Skan   return address and use a BX to get back to Thumb mode.
1189169689Skan
1190169689Skan   There are three variations of this code.  The first,
1191169689Skan   _interwork_call_via_rN(), will push the return address onto the
1192169689Skan   stack and pop it in _arm_return().  It should only be used if all
1193169689Skan   arguments are passed in registers.
1194169689Skan
1195169689Skan   The second, _interwork_r7_call_via_rN(), instead stores the return
1196169689Skan   address at [r7, #-4].  It is the caller's responsibility to ensure
1197169689Skan   that this address is valid and contains no useful data.
1198169689Skan
1199169689Skan   The third, _interwork_r11_call_via_rN(), works in the same way but
1200169689Skan   uses r11 instead of r7.  It is useful if the caller does not really
1201169689Skan   need a frame pointer.  */
120290075Sobrien	
120390075Sobrien	.text
120490075Sobrien	.align 0
120590075Sobrien
120690075Sobrien	.code   32
120790075Sobrien	.globl _arm_return
1208169689SkanLSYM(Lstart_arm_return):
1209169689Skan	cfi_start	LSYM(Lstart_arm_return) LSYM(Lend_arm_return)
1210169689Skan	cfi_push	0, 0xe, -0x8, 0x8
1211169689Skan	nop	@ This nop is for the benefit of debuggers, so that
1212169689Skan		@ backtraces will use the correct unwind information.
1213132718Skan_arm_return:
1214169689Skan	RETLDM	unwind=LSYM(Lstart_arm_return)
1215169689Skan	cfi_end	LSYM(Lend_arm_return)
121690075Sobrien
1217169689Skan	.globl _arm_return_r7
1218169689Skan_arm_return_r7:
1219169689Skan	ldr	lr, [r7, #-4]
1220169689Skan	bx	lr
1221169689Skan
1222169689Skan	.globl _arm_return_r11
1223169689Skan_arm_return_r11:
1224169689Skan	ldr	lr, [r11, #-4]
1225169689Skan	bx	lr
1226169689Skan
1227169689Skan.macro interwork_with_frame frame, register, name, return
1228169689Skan	.code	16
1229169689Skan
1230169689Skan	THUMB_FUNC_START \name
1231169689Skan
1232169689Skan	bx	pc
1233169689Skan	nop
1234169689Skan
1235169689Skan	.code	32
1236169689Skan	tst	\register, #1
1237169689Skan	streq	lr, [\frame, #-4]
1238169689Skan	adreq	lr, _arm_return_\frame
1239169689Skan	bx	\register
1240169689Skan
1241169689Skan	SIZE	(\name)
1242169689Skan.endm
1243169689Skan
1244132718Skan.macro interwork register
1245132718Skan	.code	16
124690075Sobrien
124790075Sobrien	THUMB_FUNC_START _interwork_call_via_\register
124890075Sobrien
1249132718Skan	bx	pc
125090075Sobrien	nop
1251132718Skan
1252132718Skan	.code	32
1253132718Skan	.globl LSYM(Lchange_\register)
1254132718SkanLSYM(Lchange_\register):
125590075Sobrien	tst	\register, #1
1256169689Skan	streq	lr, [sp, #-8]!
125790075Sobrien	adreq	lr, _arm_return
125890075Sobrien	bx	\register
125990075Sobrien
126090075Sobrien	SIZE	(_interwork_call_via_\register)
1261169689Skan
1262169689Skan	interwork_with_frame r7,\register,_interwork_r7_call_via_\register
1263169689Skan	interwork_with_frame r11,\register,_interwork_r11_call_via_\register
126490075Sobrien.endm
126590075Sobrien	
126690075Sobrien	interwork r0
126790075Sobrien	interwork r1
126890075Sobrien	interwork r2
126990075Sobrien	interwork r3
127090075Sobrien	interwork r4
127190075Sobrien	interwork r5
127290075Sobrien	interwork r6
127390075Sobrien	interwork r7
127490075Sobrien	interwork r8
127590075Sobrien	interwork r9
127690075Sobrien	interwork sl
127790075Sobrien	interwork fp
127890075Sobrien	interwork ip
127990075Sobrien	interwork sp
128090075Sobrien	
128190075Sobrien	/* The LR case has to be handled a little differently...  */
128290075Sobrien	.code 16
128390075Sobrien
128490075Sobrien	THUMB_FUNC_START _interwork_call_via_lr
128590075Sobrien
128690075Sobrien	bx 	pc
128790075Sobrien	nop
128890075Sobrien	
128990075Sobrien	.code 32
129090075Sobrien	.globl .Lchange_lr
129190075Sobrien.Lchange_lr:
129290075Sobrien	tst	lr, #1
1293169689Skan	stmeqdb	r13!, {lr, pc}
129490075Sobrien	mov	ip, lr
129590075Sobrien	adreq	lr, _arm_return
129690075Sobrien	bx	ip
129790075Sobrien	
129890075Sobrien	SIZE	(_interwork_call_via_lr)
129990075Sobrien	
130090075Sobrien#endif /* L_interwork_call_via_rX */
1301169689Skan#endif /* Arch supports thumb.  */
1302132718Skan
1303169689Skan#ifndef __symbian__
1304132718Skan#include "ieee754-df.S"
1305132718Skan#include "ieee754-sf.S"
1306169689Skan#include "bpabi.S"
1307169689Skan#endif /* __symbian__ */
1308