xref: /openbsd-src/sys/lib/libkern/arch/arm/divsi3.S (revision 9593dc34da13a12012033a17061c846c208061c2)
1/*	$OpenBSD: divsi3.S,v 1.7 2024/09/04 07:54:52 mglocker Exp $	*/
2/*	$NetBSD: divsi3.S,v 1.2 2001/11/13 20:06:40 chris Exp $	*/
3
4/*
5 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
6 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
9 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
11 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
15 * SUCH DAMAGE.
16 */
17
18#include <machine/asm.h>
19
20/*
21 * stack is aligned as there's a possibility of branching to L_overflow
22 * which makes a C call
23 */
24
25ENTRY(__umodsi3)
26	stmfd	sp!, {lr}
27	sub	sp, sp, #4	/* align stack */
28	bl	L_udivide
29	add	sp, sp, #4	/* unalign stack */
30	mov	r0, r1
31	ldmfd	sp!, {pc}
32
33ENTRY(__modsi3)
34	stmfd	sp!, {lr}
35	sub	sp, sp, #4	/* align stack */
36	bl	L_divide
37	add	sp, sp, #4	/* unalign stack */
38	mov	r0, r1
39	ldmfd	sp!, {pc}
40
41L_overflow:
42#if !defined(_KERNEL) && !defined(_STANDALONE)
43	mov	r0, #8			/* SIGFPE */
44	bl	PIC_SYM(raise, PLT)		/* raise it */
45	mov	r0, #0
46#else
47	/* XXX should cause a fatal error */
48	mvn	r0, #0
49#endif
50	mov	pc, lr
51
52ENTRY(__udivsi3)
53L_udivide:				/* r0 = r0 / r1; r1 = r0 % r1 */
54	eor     r0, r1, r0
55	eor     r1, r0, r1
56	eor     r0, r1, r0
57					/* r0 = r1 / r0; r1 = r1 % r0 */
58	cmp	r0, #1
59	bcc	L_overflow
60	beq	L_divide_l0
61	mov	ip, #0
62	movs	r1, r1
63	bpl	L_divide_l1
64	orr	ip, ip, #0x20000000	/* ip bit 0x20000000 = -ve r1 */
65	movs	r1, r1, lsr #1
66	orrcs	ip, ip, #0x10000000	/* ip bit 0x10000000 = bit 0 of r1 */
67	b	L_divide_l1
68
69L_divide_l0:				/* r0 == 1 */
70	mov	r0, r1
71	mov	r1, #0
72	mov	pc, lr
73
74ENTRY(__divsi3)
75L_divide:				/* r0 = r0 / r1; r1 = r0 % r1 */
76	eor     r0, r1, r0
77	eor     r1, r0, r1
78	eor     r0, r1, r0
79					/* r0 = r1 / r0; r1 = r1 % r0 */
80	cmp	r0, #1
81	bcc	L_overflow
82	beq	L_divide_l0
83	ands	ip, r0, #0x80000000
84	rsbmi	r0, r0, #0
85	ands	r2, r1, #0x80000000
86	eor	ip, ip, r2
87	rsbmi	r1, r1, #0
88	orr	ip, r2, ip, lsr #1	/* ip bit 0x40000000 = -ve division */
89					/* ip bit 0x80000000 = -ve remainder */
90
91L_divide_l1:
92	mov	r2, #1
93	mov	r3, #0
94
95	/*
96	 * If the highest bit of the dividend is set, we have to be
97	 * careful when shifting the divisor. Test this.
98	 */
99	movs	r1,r1
100	bpl	L_old_code
101
102	/*
103	 * At this point, the highest bit of r1 is known to be set.
104	 * We abuse this below in the tst instructions.
105	 */
106	tst	r1, r0 /*, lsl #0 */
107	bmi	L_divide_b1
108	tst	r1, r0, lsl #1
109	bmi	L_divide_b2
110	tst	r1, r0, lsl #2
111	bmi	L_divide_b3
112	tst	r1, r0, lsl #3
113	bmi	L_divide_b4
114	tst	r1, r0, lsl #4
115	bmi	L_divide_b5
116	tst	r1, r0, lsl #5
117	bmi	L_divide_b6
118	tst	r1, r0, lsl #6
119	bmi	L_divide_b7
120	tst	r1, r0, lsl #7
121	bmi	L_divide_b8
122	tst	r1, r0, lsl #8
123	bmi	L_divide_b9
124	tst	r1, r0, lsl #9
125	bmi	L_divide_b10
126	tst	r1, r0, lsl #10
127	bmi	L_divide_b11
128	tst	r1, r0, lsl #11
129	bmi	L_divide_b12
130	tst	r1, r0, lsl #12
131	bmi	L_divide_b13
132	tst	r1, r0, lsl #13
133	bmi	L_divide_b14
134	tst	r1, r0, lsl #14
135	bmi	L_divide_b15
136	tst	r1, r0, lsl #15
137	bmi	L_divide_b16
138	tst	r1, r0, lsl #16
139	bmi	L_divide_b17
140	tst	r1, r0, lsl #17
141	bmi	L_divide_b18
142	tst	r1, r0, lsl #18
143	bmi	L_divide_b19
144	tst	r1, r0, lsl #19
145	bmi	L_divide_b20
146	tst	r1, r0, lsl #20
147	bmi	L_divide_b21
148	tst	r1, r0, lsl #21
149	bmi	L_divide_b22
150	tst	r1, r0, lsl #22
151	bmi	L_divide_b23
152	tst	r1, r0, lsl #23
153	bmi	L_divide_b24
154	tst	r1, r0, lsl #24
155	bmi	L_divide_b25
156	tst	r1, r0, lsl #25
157	bmi	L_divide_b26
158	tst	r1, r0, lsl #26
159	bmi	L_divide_b27
160	tst	r1, r0, lsl #27
161	bmi	L_divide_b28
162	tst	r1, r0, lsl #28
163	bmi	L_divide_b29
164	tst	r1, r0, lsl #29
165	bmi	L_divide_b30
166	tst	r1, r0, lsl #30
167	bmi	L_divide_b31
168/*
169 * instead of:
170 *	tst	r1, r0, lsl #31
171 *	bmi	L_divide_b32
172 */
173	b	L_divide_b32
174
175L_old_code:
176	cmp	r1, r0
177	bcc	L_divide_b0
178	cmp	r1, r0, lsl #1
179	bcc	L_divide_b1
180	cmp	r1, r0, lsl #2
181	bcc	L_divide_b2
182	cmp	r1, r0, lsl #3
183	bcc	L_divide_b3
184	cmp	r1, r0, lsl #4
185	bcc	L_divide_b4
186	cmp	r1, r0, lsl #5
187	bcc	L_divide_b5
188	cmp	r1, r0, lsl #6
189	bcc	L_divide_b6
190	cmp	r1, r0, lsl #7
191	bcc	L_divide_b7
192	cmp	r1, r0, lsl #8
193	bcc	L_divide_b8
194	cmp	r1, r0, lsl #9
195	bcc	L_divide_b9
196	cmp	r1, r0, lsl #10
197	bcc	L_divide_b10
198	cmp	r1, r0, lsl #11
199	bcc	L_divide_b11
200	cmp	r1, r0, lsl #12
201	bcc	L_divide_b12
202	cmp	r1, r0, lsl #13
203	bcc	L_divide_b13
204	cmp	r1, r0, lsl #14
205	bcc	L_divide_b14
206	cmp	r1, r0, lsl #15
207	bcc	L_divide_b15
208	cmp	r1, r0, lsl #16
209	bcc	L_divide_b16
210	cmp	r1, r0, lsl #17
211	bcc	L_divide_b17
212	cmp	r1, r0, lsl #18
213	bcc	L_divide_b18
214	cmp	r1, r0, lsl #19
215	bcc	L_divide_b19
216	cmp	r1, r0, lsl #20
217	bcc	L_divide_b20
218	cmp	r1, r0, lsl #21
219	bcc	L_divide_b21
220	cmp	r1, r0, lsl #22
221	bcc	L_divide_b22
222	cmp	r1, r0, lsl #23
223	bcc	L_divide_b23
224	cmp	r1, r0, lsl #24
225	bcc	L_divide_b24
226	cmp	r1, r0, lsl #25
227	bcc	L_divide_b25
228	cmp	r1, r0, lsl #26
229	bcc	L_divide_b26
230	cmp	r1, r0, lsl #27
231	bcc	L_divide_b27
232	cmp	r1, r0, lsl #28
233	bcc	L_divide_b28
234	cmp	r1, r0, lsl #29
235	bcc	L_divide_b29
236	cmp	r1, r0, lsl #30
237	bcc	L_divide_b30
238L_divide_b32:
239	cmp	r1, r0, lsl #31
240	subhs	r1, r1,r0, lsl #31
241	addhs	r3, r3,r2, lsl #31
242L_divide_b31:
243	cmp	r1, r0, lsl #30
244	subhs	r1, r1,r0, lsl #30
245	addhs	r3, r3,r2, lsl #30
246L_divide_b30:
247	cmp	r1, r0, lsl #29
248	subhs	r1, r1,r0, lsl #29
249	addhs	r3, r3,r2, lsl #29
250L_divide_b29:
251	cmp	r1, r0, lsl #28
252	subhs	r1, r1,r0, lsl #28
253	addhs	r3, r3,r2, lsl #28
254L_divide_b28:
255	cmp	r1, r0, lsl #27
256	subhs	r1, r1,r0, lsl #27
257	addhs	r3, r3,r2, lsl #27
258L_divide_b27:
259	cmp	r1, r0, lsl #26
260	subhs	r1, r1,r0, lsl #26
261	addhs	r3, r3,r2, lsl #26
262L_divide_b26:
263	cmp	r1, r0, lsl #25
264	subhs	r1, r1,r0, lsl #25
265	addhs	r3, r3,r2, lsl #25
266L_divide_b25:
267	cmp	r1, r0, lsl #24
268	subhs	r1, r1,r0, lsl #24
269	addhs	r3, r3,r2, lsl #24
270L_divide_b24:
271	cmp	r1, r0, lsl #23
272	subhs	r1, r1,r0, lsl #23
273	addhs	r3, r3,r2, lsl #23
274L_divide_b23:
275	cmp	r1, r0, lsl #22
276	subhs	r1, r1,r0, lsl #22
277	addhs	r3, r3,r2, lsl #22
278L_divide_b22:
279	cmp	r1, r0, lsl #21
280	subhs	r1, r1,r0, lsl #21
281	addhs	r3, r3,r2, lsl #21
282L_divide_b21:
283	cmp	r1, r0, lsl #20
284	subhs	r1, r1,r0, lsl #20
285	addhs	r3, r3,r2, lsl #20
286L_divide_b20:
287	cmp	r1, r0, lsl #19
288	subhs	r1, r1,r0, lsl #19
289	addhs	r3, r3,r2, lsl #19
290L_divide_b19:
291	cmp	r1, r0, lsl #18
292	subhs	r1, r1,r0, lsl #18
293	addhs	r3, r3,r2, lsl #18
294L_divide_b18:
295	cmp	r1, r0, lsl #17
296	subhs	r1, r1,r0, lsl #17
297	addhs	r3, r3,r2, lsl #17
298L_divide_b17:
299	cmp	r1, r0, lsl #16
300	subhs	r1, r1,r0, lsl #16
301	addhs	r3, r3,r2, lsl #16
302L_divide_b16:
303	cmp	r1, r0, lsl #15
304	subhs	r1, r1,r0, lsl #15
305	addhs	r3, r3,r2, lsl #15
306L_divide_b15:
307	cmp	r1, r0, lsl #14
308	subhs	r1, r1,r0, lsl #14
309	addhs	r3, r3,r2, lsl #14
310L_divide_b14:
311	cmp	r1, r0, lsl #13
312	subhs	r1, r1,r0, lsl #13
313	addhs	r3, r3,r2, lsl #13
314L_divide_b13:
315	cmp	r1, r0, lsl #12
316	subhs	r1, r1,r0, lsl #12
317	addhs	r3, r3,r2, lsl #12
318L_divide_b12:
319	cmp	r1, r0, lsl #11
320	subhs	r1, r1,r0, lsl #11
321	addhs	r3, r3,r2, lsl #11
322L_divide_b11:
323	cmp	r1, r0, lsl #10
324	subhs	r1, r1,r0, lsl #10
325	addhs	r3, r3,r2, lsl #10
326L_divide_b10:
327	cmp	r1, r0, lsl #9
328	subhs	r1, r1,r0, lsl #9
329	addhs	r3, r3,r2, lsl #9
330L_divide_b9:
331	cmp	r1, r0, lsl #8
332	subhs	r1, r1,r0, lsl #8
333	addhs	r3, r3,r2, lsl #8
334L_divide_b8:
335	cmp	r1, r0, lsl #7
336	subhs	r1, r1,r0, lsl #7
337	addhs	r3, r3,r2, lsl #7
338L_divide_b7:
339	cmp	r1, r0, lsl #6
340	subhs	r1, r1,r0, lsl #6
341	addhs	r3, r3,r2, lsl #6
342L_divide_b6:
343	cmp	r1, r0, lsl #5
344	subhs	r1, r1,r0, lsl #5
345	addhs	r3, r3,r2, lsl #5
346L_divide_b5:
347	cmp	r1, r0, lsl #4
348	subhs	r1, r1,r0, lsl #4
349	addhs	r3, r3,r2, lsl #4
350L_divide_b4:
351	cmp	r1, r0, lsl #3
352	subhs	r1, r1,r0, lsl #3
353	addhs	r3, r3,r2, lsl #3
354L_divide_b3:
355	cmp	r1, r0, lsl #2
356	subhs	r1, r1,r0, lsl #2
357	addhs	r3, r3,r2, lsl #2
358L_divide_b2:
359	cmp	r1, r0, lsl #1
360	subhs	r1, r1,r0, lsl #1
361	addhs	r3, r3,r2, lsl #1
362L_divide_b1:
363	cmp	r1, r0
364	subhs	r1, r1, r0
365	addhs	r3, r3, r2
366L_divide_b0:
367
368	tst	ip, #0x20000000
369	bne	L_udivide_l1
370	mov	r0, r3
371	cmp	ip, #0
372	rsbmi	r1, r1, #0
373	movs	ip, ip, lsl #1
374	bicmi	r0, r0, #0x80000000	/* Fix in case we divided 0x80000000 */
375	rsbmi	r0, r0, #0
376	mov	pc, lr
377
378L_udivide_l1:
379	tst	ip, #0x10000000
380	mov	r1, r1, lsl #1
381	orrne	r1, r1, #1
382	mov	r3, r3, lsl #1
383	cmp	r1, r0
384	subhs	r1, r1, r0
385	addhs	r3, r3, r2
386	mov	r0, r3
387	mov	pc, lr
388
389STRONG_ALIAS(__aeabi_idiv, __divsi3)
390STRONG_ALIAS(__aeabi_idivmod, __divsi3)
391STRONG_ALIAS(__aeabi_uidiv, __udivsi3)
392STRONG_ALIAS(__aeabi_uidivmod, __udivsi3)
393