1210284Sjmallett/*-
2232812Sjmallett * Copyright (c) 2012 The NetBSD Foundation, Inc.
3215990Sjmallett * All rights reserved.
4210284Sjmallett *
5210284Sjmallett * This code is derived from software contributed to The NetBSD Foundation
6215990Sjmallett * by Matt Thomas of 3am Software Foundry.
7215990Sjmallett *
8215990Sjmallett * Redistribution and use in source and binary forms, with or without
9210284Sjmallett * modification, are permitted provided that the following conditions
10215990Sjmallett * are met:
11215990Sjmallett * 1. Redistributions of source code must retain the above copyright
12210284Sjmallett *    notice, this list of conditions and the following disclaimer.
13215990Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
14215990Sjmallett *    notice, this list of conditions and the following disclaimer in the
15215990Sjmallett *    documentation and/or other materials provided with the distribution.
16215990Sjmallett *
17215990Sjmallett * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18232812Sjmallett * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19215990Sjmallett * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20215990Sjmallett * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21215990Sjmallett * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22215990Sjmallett * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23215990Sjmallett * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24215990Sjmallett * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25215990Sjmallett * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26215990Sjmallett * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27215990Sjmallett * POSSIBILITY OF SUCH DAMAGE.
28215990Sjmallett */
29232812Sjmallett
30215990Sjmallett#include <machine/asm.h>
31215990Sjmallett
32215990SjmallettRCSID("$NetBSD: __aeabi_ldivmod.S,v 1.12 2013/08/19 03:27:34 matt Exp $")
33215990Sjmallett
34215990Sjmallett#ifdef __ARMEB__
35215990Sjmallett#define	ALO	r1	/* incoming numerator, outgoing quotient */
36215990Sjmallett#define	AHI	r0	/* incoming numerator, outgoing quotient */
37215990Sjmallett#define	BLO	r3	/* incoming denominator, outgoing remainder */
38210284Sjmallett#define	BHI	r2	/* incoming denominator, outgoing remainder */
39210284Sjmallett#else
40210284Sjmallett#define	ALO	r0	/* incoming numerator, outgoing quotient */
41210284Sjmallett#define	AHI	r1	/* incoming numerator, outgoing quotient */
42210284Sjmallett#define	BLO	r2	/* incoming denominator, outgoing remainder */
43210284Sjmallett#define	BHI	r3	/* incoming denominator, outgoing remainder */
44215990Sjmallett#endif
45210284Sjmallett
46210284SjmallettENTRY(__aeabi_ldivmod)
47210284Sjmallett#ifdef __ARM_EABI__
48210284Sjmallett# if !defined(__ARM_DWARF_EH__)
49232812Sjmallett	.fnstart
50210284Sjmallett# endif
51210284Sjmallett	.cfi_startproc
52210284Sjmallett#endif
53210284Sjmallett#if !defined(_KERNEL) && !defined(_STANDALONE)
54210284Sjmallett#if !defined(__thumb__)
55210284Sjmallett	orrs	ip, BLO, BHI
56210284Sjmallett	beq	.Ldivbyzero
57210284Sjmallett#elif defined(_ARM_ARCH_T2)
58210284Sjmallett	cbnz	BLO, 1f
59210284Sjmallett	cbz	BHI, .Ldivbyzero
60210284Sjmallett#else
61210284Sjmallett	cmp	BLO, #0
62210284Sjmallett	bne	1f
63210284Sjmallett	cmp	BHI, #0
64210284Sjmallett	beq	.Ldivbyzero
65232812Sjmallett#endif
66210284Sjmallett1:
67210284Sjmallett#endif
68210284Sjmallett
69210284Sjmallett	push	{r4-r6, lr}
70210284Sjmallett#ifdef __ARM_EABI__
71210284Sjmallett	.cfi_def_cfa_offset 16
72210284Sjmallett	.cfi_offset 14, -4
73210284Sjmallett	.cfi_offset 6, -8
74210284Sjmallett	.cfi_offset 5, -12
75210284Sjmallett	.cfi_offset 4, -16
76210284Sjmallett#endif
77210284Sjmallett#define	NEG	r5
78215990Sjmallett	movs	NEG, #0
79232812Sjmallett
80210284Sjmallett	cmp	BHI, #0
81210284Sjmallett	bge	2f
82210284Sjmallett	movs	NEG, #1		/* flip quotient sign */
83210284Sjmallett	bl	.Lnegate_b
84210284Sjmallett	bcs	.Lmaxdenom
85210284Sjmallett
86210284Sjmallett2:
87210284Sjmallett	cmp	AHI, #0
88210284Sjmallett#ifdef __thumb__
89210284Sjmallett	bge	3f
90210284Sjmallett	movs	r4, #3
91210284Sjmallett	eors	NEG, NEG, r4	/* flip quotient sign, flip remainder sign */
92210284Sjmallett	bl	.Lnegate_a
93210284Sjmallett3:
94210284Sjmallett#else
95210284Sjmallett	eorlt	NEG, NEG, #3	/* flip quotient sign, flip remainder sign */
96210284Sjmallett	bllt	.Lnegate_a
97210284Sjmallett#endif
98210284Sjmallett
99210284Sjmallett	/*
100210284Sjmallett	 * Arguments are setup, allocate some stack for the remainder
101210284Sjmallett	 * and call __qdivrem for the heavy lifting.
102210284Sjmallett	 */
103210284Sjmallett#ifdef __ARM_EABI__
104210284Sjmallett	.cfi_def_cfa_offset 32
105210284Sjmallett#endif
106210284Sjmallett	sub	sp, sp, #16
107210284Sjmallett#if !defined(__thumb__) || defined(_ARM_ARCH_T2)
108210284Sjmallett	adds	r4, sp, #8
109210284Sjmallett#else
110210284Sjmallett	mov	r4, sp
111210284Sjmallett	adds	r4, r4, #8
112210284Sjmallett#endif
113210284Sjmallett	str	r4, [sp]
114210284Sjmallett	bl	PLT_SYM(__qdivrem)
115210284Sjmallett	add	sp, sp, #8
116210284Sjmallett#ifdef __ARM_EABI__
117210284Sjmallett	.cfi_def_cfa_offset 24
118210284Sjmallett	.cfi_offset 3, -20
119210284Sjmallett	.cfi_offset 2, -24
120210284Sjmallett#endif
121210284Sjmallett
122210284Sjmallett	/*
123250428Simp	 * The quotient is already in the right place and neither value
124250428Simp	 * needs its sign flipped.
125210284Sjmallett	 */
126250428Simp#if defined(__thumb__) && defined(_ARM_ARCH_T2)
127232812Sjmallett	cbz	NEG, .Lnegate_neither
128232812Sjmallett#else
129232812Sjmallett	cmp	NEG, #0		/* any signs to flip? */
130232812Sjmallett	beq	.Lnegate_neither
131232812Sjmallett#endif
132232812Sjmallett
133232812Sjmallett	cmp	NEG, #2		/* does remainder need to be negative? */
134232812Sjmallett	beq	.Lnegate_b_only	/* 2 means b only */
135232812Sjmallett	bgt	.Lnegate_both	/* 3 means both */
136232812Sjmallett.Lnegate_a_only:
137232812Sjmallett	bl	.Lnegate_a	/* 1 means a only */
138210284Sjmallett.Lnegate_neither:
139232812Sjmallett	pop	{r2-r6, pc}	/* grab b from stack */
140232812Sjmallett.Lnegate_both:
141232812Sjmallett	bl	.Lnegate_a
142232812Sjmallett.Lnegate_b_only:
143210284Sjmallett	pop	{r2-r3}		/* get remainder */
144232812Sjmallett#ifdef __ARM_EABI__
145232812Sjmallett	.cfi_def_cfa_offset 16
146232812Sjmallett#endif
147232812Sjmallett	bl	.Lnegate_b	/* negate it */
148232812Sjmallett	pop	{r4-r6, pc}
149232812Sjmallett
150232812Sjmallett	.align	0
151232812Sjmallett.Lnegate_a:
152232812Sjmallett#ifdef __thumb__
153232812Sjmallett	movs	r4, AHI
154232812Sjmallett	movs	AHI, #0
155232812Sjmallett	negs	ALO, ALO
156232812Sjmallett	sbcs	AHI, AHI, r4
157232812Sjmallett#else
158232812Sjmallett	negs	ALO, ALO
159232812Sjmallett	rsc	AHI, AHI, #0
160232812Sjmallett#endif
161232812Sjmallett	RET
162232812Sjmallett
163232812Sjmallett	.align	0
164232812Sjmallett.Lnegate_b:
165232812Sjmallett#ifdef __thumb__
166232812Sjmallett	movs	r4, BHI
167232812Sjmallett	movs	BHI, #0
168232812Sjmallett	negs	BLO, BLO
169232812Sjmallett	sbcs	BHI, BHI, r4
170232812Sjmallett#else
171232812Sjmallett	negs	BLO, BLO
172232812Sjmallett	rsc	BHI, BHI, #0
173232812Sjmallett#endif
174232812Sjmallett	RET
175232812Sjmallett
176232812Sjmallett	.align	0
177232812Sjmallett.Lmaxdenom:
178232812Sjmallett	/*
179232812Sjmallett	 * We had a carry so the denominator must have INT64_MIN
180232812Sjmallett	 * Also BLO and BHI never changed values so we can use
181232812Sjmallett	 * them to see if the numerator has the same value.  We
182232812Sjmallett	 * don't have to worry about sign.
183232812Sjmallett	 */
184232812Sjmallett	cmp	BHI, AHI
185232812Sjmallett#ifdef __thumb__
186232812Sjmallett	bne	1f
187232812Sjmallett	cmp	BLO, ALO
188232812Sjmallett#else
189232812Sjmallett	cmpeq	BLO, ALO
190232812Sjmallett#endif
191215990Sjmallett	bne	1f
192210284Sjmallett
193215990Sjmallett	/*
194215990Sjmallett	 * They were equal, so we return a quotient of 1 and remainder of 0.
195210284Sjmallett	 */
196210284Sjmallett	movs	ALO, #1
197210284Sjmallett	movs	AHI, #0
198210284Sjmallett	movs	BLO, #0
199210284Sjmallett	movs	BHI, #0
200210284Sjmallett	pop	{r4-r6, pc}
201210284Sjmallett
202210284Sjmallett	/*
203210284Sjmallett	 * Our remainder must be the numerator and our quotient is 0.
204210284Sjmallett	 */
205210284Sjmallett	.align	0
206210284Sjmallett1:	movs	BLO, ALO
207210284Sjmallett	movs	BHI, AHI
208210284Sjmallett	movs	ALO, #0
209210284Sjmallett	movs	AHI, #0
210210284Sjmallett	pop	{r4-r6, pc}
211210284Sjmallett
212210284Sjmallett#if !defined(_KERNEL) && !defined(_STANDALONE)
213210284Sjmallett	.align	0
214232812Sjmallett.Ldivbyzero:
215210284Sjmallett	push	{r0-r1,r4,lr}
216210284Sjmallett#ifdef __ARM_EABI__
217210284Sjmallett# if !defined(__ARM_DWARF_EH__)
218210284Sjmallett	.save	{r0-r1,r4,lr}
219210284Sjmallett# endif
220210284Sjmallett	.cfi_def_cfa_offset 16
221210284Sjmallett	.cfi_offset 14, -4
222250428Simp	.cfi_offset  4, -8
223250428Simp#endif
224250428Simp	cmp	AHI, #0
225250428Simp#if !defined(__thumb__) || defined(_ARM_ARCH_T2)
226250428Simp#ifdef __thumb__
227250428Simp	ittee	ge
228210284Sjmallett#endif
229210284Sjmallett	mvnge	ALO, #0
230210284Sjmallett	mvnge	AHI, #0x80000000
231210284Sjmallett	movlt	ALO, #0
232250428Simp	movlt	AHI, #0x80000000
233210284Sjmallett#else
234210284Sjmallett	blt	1f
235210284Sjmallett	movs	ALO, #0
236210284Sjmallett	mvns	ALO, ALO
237210284Sjmallett	mov	AHI, ALO
238210284Sjmallett	lsrs	AHI, AHI, #1
239210284Sjmallett	b	2f
240210284Sjmallett1:
241210284Sjmallett	movs	ALO, #0
242210284Sjmallett	movs	AHI, #1
243210284Sjmallett	lsls	AHI, AHI, #31
244210284Sjmallett2:
245215990Sjmallett#endif /* __thumb__ && !_ARM_ARCH_T2 */
246215990Sjmallett	bl	PLT_SYM(__aeabi_ldiv0)
247215990Sjmallett	pop	{r2-r4, pc}
248215990Sjmallett#endif	/* !_KERNEL && !_STANDALONE */
249215990Sjmallett#ifdef __ARM_EABI__
250215990Sjmallett	.cfi_endproc
251215990Sjmallett# if !defined(__ARM_DWARF_EH__)
252215990Sjmallett	.fnend
253215990Sjmallett# endif
254232812Sjmallett#endif
255232812SjmallettEND(__aeabi_ldivmod)
256232812Sjmallett