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.13 2014/05/06 16:02:11 joerg 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# if !defined(__ARM_DWARF_EH__)
49	.fnstart
50# endif
51	.cfi_startproc
52#endif
53#if !defined(_KERNEL) && !defined(_STANDALONE)
54#if !defined(__thumb__)
55	orrs	ip, BLO, BHI
56	beq	.Ldivbyzero
57#elif defined(_ARM_ARCH_T2)
58	cbnz	BLO, 1f
59	cbz	BHI, .Ldivbyzero
60#else
61	cmp	BLO, #0
62	bne	1f
63	cmp	BHI, #0
64	beq	.Ldivbyzero
65#endif
661:
67#endif
68
69	push	{r4-r6, lr}
70#ifdef __ARM_EABI__
71	.cfi_def_cfa_offset 16
72	.cfi_offset 14, -4
73	.cfi_offset 6, -8
74	.cfi_offset 5, -12
75	.cfi_offset 4, -16
76#endif
77#define	NEG	r5
78	movs	NEG, #0
79
80	cmp	BHI, #0
81	bge	2f
82	movs	NEG, #1		/* flip quotient sign */
83	bl	.Lnegate_b
84	bcs	.Lmaxdenom
85
862:
87	cmp	AHI, #0
88#ifdef __thumb__
89	bge	3f
90	movs	r4, #3
91	eors	NEG, NEG, r4	/* flip quotient sign, flip remainder sign */
92	bl	.Lnegate_a
933:
94#else
95	eorlt	NEG, NEG, #3	/* flip quotient sign, flip remainder sign */
96	bllt	.Lnegate_a
97#endif
98
99	/*
100	 * Arguments are setup, allocate some stack for the remainder
101	 * and call __qdivrem for the heavy lifting.
102	 */
103#ifdef __ARM_EABI__
104	.cfi_def_cfa_offset 32
105#endif
106	sub	sp, sp, #16
107#if !defined(__thumb__) || defined(_ARM_ARCH_T2)
108	adds	r4, sp, #8
109#else
110	mov	r4, sp
111	adds	r4, r4, #8
112#endif
113	str	r4, [sp]
114	bl	PLT_SYM(__qdivrem)
115	add	sp, sp, #8
116#ifdef __ARM_EABI__
117	.cfi_def_cfa_offset 24
118	.cfi_offset 3, -20
119	.cfi_offset 2, -24
120#endif
121
122	/*
123	 * The quotient is already in the right place and neither value
124	 * needs its sign flipped.
125	 */
126#if defined(__thumb__) && defined(_ARM_ARCH_T2)
127	cbz	NEG, .Lnegate_neither
128#else
129	cmp	NEG, #0		/* any signs to flip? */
130	beq	.Lnegate_neither
131#endif
132
133	cmp	NEG, #2		/* does remainder need to be negative? */
134	beq	.Lnegate_b_only	/* 2 means b only */
135	bgt	.Lnegate_both	/* 3 means both */
136.Lnegate_a_only:
137	bl	.Lnegate_a	/* 1 means a only */
138.Lnegate_neither:
139	pop	{r2-r6, pc}	/* grab b from stack */
140.Lnegate_both:
141	bl	.Lnegate_a
142.Lnegate_b_only:
143	pop	{r2-r3}		/* get remainder */
144#ifdef __ARM_EABI__
145	.cfi_def_cfa_offset 16
146#endif
147	bl	.Lnegate_b	/* negate it */
148	pop	{r4-r6, pc}
149
150	.align	0
151.Lnegate_a:
152#ifdef __thumb__
153	movs	r4, AHI
154	movs	AHI, #0
155	negs	ALO, ALO
156	sbcs	AHI, AHI, r4
157#else
158	negs	ALO, ALO
159	rsc	AHI, AHI, #0
160#endif
161	RET
162
163	.align	0
164.Lnegate_b:
165#ifdef __thumb__
166	movs	r4, BHI
167	movs	BHI, #0
168	negs	BLO, BLO
169	sbcs	BHI, BHI, r4
170#else
171	negs	BLO, BLO
172	rsc	BHI, BHI, #0
173#endif
174	RET
175
176	.align	0
177.Lmaxdenom:
178	/*
179	 * We had a carry so the denominator must have INT64_MIN
180	 * Also BLO and BHI never changed values so we can use
181	 * them to see if the numerator has the same value.  We
182	 * don't have to worry about sign.
183	 */
184	cmp	BHI, AHI
185#ifdef __thumb__
186	bne	1f
187	cmp	BLO, ALO
188#else
189	cmpeq	BLO, ALO
190#endif
191	bne	1f
192
193	/*
194	 * They were equal, so we return a quotient of 1 and remainder of 0.
195	 */
196	movs	ALO, #1
197	movs	AHI, #0
198	movs	BLO, #0
199	movs	BHI, #0
200	pop	{r4-r6, pc}
201
202	/*
203	 * Our remainder must be the numerator and our quotient is 0.
204	 */
205	.align	0
2061:	movs	BLO, ALO
207	movs	BHI, AHI
208	movs	ALO, #0
209	movs	AHI, #0
210	pop	{r4-r6, pc}
211
212#if !defined(_KERNEL) && !defined(_STANDALONE)
213	.align	0
214.Ldivbyzero:
215	push	{r0-r1,r4,lr}
216#ifdef __ARM_EABI__
217# if !defined(__ARM_DWARF_EH__)
218	.save	{r0-r1,r4,lr}
219# endif
220	.cfi_def_cfa_offset 16
221	.cfi_offset 14, -4
222	.cfi_offset  4, -8
223#endif
224	cmp	AHI, #0
225#if !defined(__thumb__) || defined(_ARM_ARCH_T2)
226#ifdef __thumb__
227	ittee	ge
228#endif
229	mvnge	ALO, #0
230	mvnge	AHI, #0x80000000
231	movlt	ALO, #0
232	movlt	AHI, #0x80000000
233#else
234	blt	1f
235	movs	ALO, #0
236	mvns	ALO, ALO
237	mov	AHI, ALO
238	lsrs	AHI, AHI, #1
239	b	2f
2401:
241	movs	ALO, #0
242	movs	AHI, #1
243	lsls	AHI, AHI, #31
2442:
245#endif /* __thumb__ && !_ARM_ARCH_T2 */
246	bl	PLT_SYM(__aeabi_ldiv0)
247	pop	{r2-r4, pc}
248#endif	/* !_KERNEL && !_STANDALONE */
249#ifdef __ARM_EABI__
250	.cfi_endproc
251# if !defined(__ARM_DWARF_EH__)
252	.fnend
253# endif
254#endif
255END(__aeabi_ldivmod)
256