__aeabi_ldivmod.S revision 1.12 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
32 RCSID("$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
46 ENTRY(__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
64 1:
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
84 2:
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
91 3:
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
204 1: 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
236 1:
237 movs ALO, #0
238 movs AHI, #1
239 lsls AHI, AHI, #31
240 2:
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
249 END(__aeabi_ldivmod)
250