__aeabi_ldivmod.S revision 1.13 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.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
46 ENTRY(__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
66 1:
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
86 2:
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
93 3:
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
206 1: 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
240 1:
241 movs ALO, #0
242 movs AHI, #1
243 lsls AHI, AHI, #31
244 2:
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
255 END(__aeabi_ldivmod)
256