1/*-
2 * Copyright (c) 2012 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Matt Thomas of 3am Software Foundry.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <machine/asm.h>
31
32RCSID("$NetBSD: __aeabi_ldivmod.S,v 1.12 2013/08/19 03:27:34 matt Exp $")
33
34#ifdef __ARMEB__
35#define	ALO	r1	/* incoming numerator, outgoing quotient */
36#define	AHI	r0	/* incoming numerator, outgoing quotient */
37#define	BLO	r3	/* incoming denominator, outgoing remainder */
38#define	BHI	r2	/* incoming denominator, outgoing remainder */
39#else
40#define	ALO	r0	/* incoming numerator, outgoing quotient */
41#define	AHI	r1	/* incoming numerator, outgoing quotient */
42#define	BLO	r2	/* incoming denominator, outgoing remainder */
43#define	BHI	r3	/* incoming denominator, outgoing remainder */
44#endif
45
46ENTRY(__aeabi_ldivmod)
47#ifdef __ARM_EABI__
48	.fnstart
49	.cfi_startproc
50#endif
51#if !defined(_KERNEL) && !defined(_STANDALONE)
52#if !defined(__thumb__)
53	orrs	ip, BLO, BHI
54	beq	.Ldivbyzero
55#elif defined(_ARM_ARCH_T2)
56	cbnz	BLO, 1f
57	cbz	BHI, .Ldivbyzero
58#else
59	cmp	BLO, #0
60	bne	1f
61	cmp	BHI, #0
62	beq	.Ldivbyzero
63#endif
641:
65#endif
66
67	push	{r4-r6, lr}
68#ifdef __ARM_EABI__
69	.cfi_def_cfa_offset 16
70	.cfi_offset 14, -4
71	.cfi_offset 6, -8
72	.cfi_offset 5, -12
73	.cfi_offset 4, -16
74#endif
75#define	NEG	r5
76	movs	NEG, #0
77
78	cmp	BHI, #0
79	bge	2f
80	movs	NEG, #1		/* flip quotient sign */
81	bl	.Lnegate_b
82	bcs	.Lmaxdenom
83
842:
85	cmp	AHI, #0
86#ifdef __thumb__
87	bge	3f
88	movs	r4, #3
89	eors	NEG, NEG, r4	/* flip quotient sign, flip remainder sign */
90	bl	.Lnegate_a
913:
92#else
93	eorlt	NEG, NEG, #3	/* flip quotient sign, flip remainder sign */
94	bllt	.Lnegate_a
95#endif
96
97	/*
98	 * Arguments are setup, allocate some stack for the remainder
99	 * and call __qdivrem for the heavy lifting.
100	 */
101#ifdef __ARM_EABI__
102	.cfi_def_cfa_offset 32
103#endif
104	sub	sp, sp, #16
105#if !defined(__thumb__) || defined(_ARM_ARCH_T2)
106	adds	r4, sp, #8
107#else
108	mov	r4, sp
109	adds	r4, r4, #8
110#endif
111	str	r4, [sp]
112	bl	PLT_SYM(__qdivrem)
113	add	sp, sp, #8
114#ifdef __ARM_EABI__
115	.cfi_def_cfa_offset 24
116	.cfi_offset 3, -20
117	.cfi_offset 2, -24
118#endif
119
120	/*
121	 * The quotient is already in the right place and neither value
122	 * needs its sign flipped.
123	 */
124#if defined(__thumb__) && defined(_ARM_ARCH_T2)
125	cbz	NEG, .Lnegate_neither
126#else
127	cmp	NEG, #0		/* any signs to flip? */
128	beq	.Lnegate_neither
129#endif
130
131	cmp	NEG, #2		/* does remainder need to be negative? */
132	beq	.Lnegate_b_only	/* 2 means b only */
133	bgt	.Lnegate_both	/* 3 means both */
134.Lnegate_a_only:
135	bl	.Lnegate_a	/* 1 means a only */
136.Lnegate_neither:
137	pop	{r2-r6, pc}	/* grab b from stack */
138.Lnegate_both:
139	bl	.Lnegate_a
140.Lnegate_b_only:
141	pop	{r2-r3}		/* get remainder */
142#ifdef __ARM_EABI__
143	.cfi_def_cfa_offset 16
144#endif
145	bl	.Lnegate_b	/* negate it */
146	pop	{r4-r6, pc}
147
148	.align	0
149.Lnegate_a:
150#ifdef __thumb__
151	movs	r4, AHI
152	movs	AHI, #0
153	negs	ALO, ALO
154	sbcs	AHI, AHI, r4
155#else
156	negs	ALO, ALO
157	rsc	AHI, AHI, #0
158#endif
159	RET
160
161	.align	0
162.Lnegate_b:
163#ifdef __thumb__
164	movs	r4, BHI
165	movs	BHI, #0
166	negs	BLO, BLO
167	sbcs	BHI, BHI, r4
168#else
169	negs	BLO, BLO
170	rsc	BHI, BHI, #0
171#endif
172	RET
173
174	.align	0
175.Lmaxdenom:
176	/*
177	 * We had a carry so the denominator must have INT64_MIN
178	 * Also BLO and BHI never changed values so we can use
179	 * them to see if the numerator has the same value.  We
180	 * don't have to worry about sign.
181	 */
182	cmp	BHI, AHI
183#ifdef __thumb__
184	bne	1f
185	cmp	BLO, ALO
186#else
187	cmpeq	BLO, ALO
188#endif
189	bne	1f
190
191	/*
192	 * They were equal, so we return a quotient of 1 and remainder of 0.
193	 */
194	movs	ALO, #1
195	movs	AHI, #0
196	movs	BLO, #0
197	movs	BHI, #0
198	pop	{r4-r6, pc}
199
200	/*
201	 * Our remainder must be the numerator and our quotient is 0.
202	 */
203	.align	0
2041:	movs	BLO, ALO
205	movs	BHI, AHI
206	movs	ALO, #0
207	movs	AHI, #0
208	pop	{r4-r6, pc}
209
210#if !defined(_KERNEL) && !defined(_STANDALONE)
211	.align	0
212.Ldivbyzero:
213	push	{r0-r1,r4,lr}
214#ifdef __ARM_EABI__
215	.save	{r0-r1,r4,lr}
216	.cfi_def_cfa_offset 16
217	.cfi_offset 14, -4
218	.cfi_offset  4, -8
219#endif
220	cmp	AHI, #0
221#if !defined(__thumb__) || defined(_ARM_ARCH_T2)
222#ifdef __thumb__
223	ittee	ge
224#endif
225	mvnge	ALO, #0
226	mvnge	AHI, #0x80000000
227	movlt	ALO, #0
228	movlt	AHI, #0x80000000
229#else
230	blt	1f
231	movs	ALO, #0
232	mvns	ALO, ALO
233	mov	AHI, ALO
234	lsrs	AHI, AHI, #1
235	b	2f
2361:
237	movs	ALO, #0
238	movs	AHI, #1
239	lsls	AHI, AHI, #31
2402:
241#endif /* __thumb__ && !_ARM_ARCH_T2 */
242	bl	PLT_SYM(__aeabi_ldiv0)
243	pop	{r2-r4, pc}
244#endif	/* !_KERNEL && !_STANDALONE */
245#ifdef __ARM_EABI__
246	.cfi_endproc
247	.fnend
248#endif
249END(__aeabi_ldivmod)
250