xref: /netbsd-src/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/udivmodsi4.S (revision ef84fd3bd8895f4e6be1e38baf19e6dc3255bc64)
1156cd587Sjoerg/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
2156cd587Sjoerg *
3156cd587Sjoerg *                     The LLVM Compiler Infrastructure
4156cd587Sjoerg *
5156cd587Sjoerg * This file is dual licensed under the MIT and the University of Illinois Open
6156cd587Sjoerg * Source Licenses. See LICENSE.TXT for details.
7156cd587Sjoerg *
8156cd587Sjoerg *===----------------------------------------------------------------------===//
9156cd587Sjoerg *
10156cd587Sjoerg * This file implements the __udivmodsi4 (32-bit unsigned integer divide and
11156cd587Sjoerg * modulus) function for the ARM 32-bit architecture.
12156cd587Sjoerg *
13156cd587Sjoerg *===----------------------------------------------------------------------===*/
14156cd587Sjoerg
15156cd587Sjoerg#include "../assembly.h"
16156cd587Sjoerg
17156cd587Sjoerg	.syntax unified
18156cd587Sjoerg	.text
19190e92d8Sjoerg
20190e92d8Sjoerg#if __ARM_ARCH_ISA_THUMB == 2
21190e92d8Sjoerg	.thumb
22190e92d8Sjoerg#endif
23190e92d8Sjoerg
24190e92d8Sjoerg@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
25190e92d8Sjoerg@                           unsigned int *remainder)
26190e92d8Sjoerg@   Calculate the quotient and remainder of the (unsigned) division.  The return
27190e92d8Sjoerg@   value is the quotient, the remainder is placed in the variable.
28190e92d8Sjoerg
29156cd587Sjoerg	.p2align 2
30*ef84fd3bSjoerg#if __ARM_ARCH_ISA_THUMB == 2
31*ef84fd3bSjoergDEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
32*ef84fd3bSjoerg#else
33156cd587SjoergDEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
34*ef84fd3bSjoerg#endif
35156cd587Sjoerg#if __ARM_ARCH_EXT_IDIV__
36156cd587Sjoerg	tst     r1, r1
37156cd587Sjoerg	beq     LOCAL_LABEL(divby0)
38156cd587Sjoerg	mov 	r3, r0
39156cd587Sjoerg	udiv	r0, r3, r1
40156cd587Sjoerg	mls 	r1, r0, r1, r3
41156cd587Sjoerg	str 	r1, [r2]
42156cd587Sjoerg	bx  	lr
43156cd587Sjoerg#else
44156cd587Sjoerg	cmp	r1, #1
45156cd587Sjoerg	bcc	LOCAL_LABEL(divby0)
46156cd587Sjoerg	beq	LOCAL_LABEL(divby1)
47156cd587Sjoerg	cmp	r0, r1
48156cd587Sjoerg	bcc	LOCAL_LABEL(quotient0)
49156cd587Sjoerg	/*
50156cd587Sjoerg	 * Implement division using binary long division algorithm.
51156cd587Sjoerg	 *
52156cd587Sjoerg	 * r0 is the numerator, r1 the denominator.
53156cd587Sjoerg	 *
54156cd587Sjoerg	 * The code before JMP computes the correct shift I, so that
55156cd587Sjoerg	 * r0 and (r1 << I) have the highest bit set in the same position.
56156cd587Sjoerg	 * At the time of JMP, ip := .Ldiv0block - 12 * I.
57156cd587Sjoerg	 * This depends on the fixed instruction size of block.
58190e92d8Sjoerg	 * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
59156cd587Sjoerg	 *
60156cd587Sjoerg	 * block(shift) implements the test-and-update-quotient core.
61156cd587Sjoerg	 * It assumes (r0 << shift) can be computed without overflow and
62156cd587Sjoerg	 * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
63156cd587Sjoerg	 */
64156cd587Sjoerg
65156cd587Sjoerg#  ifdef __ARM_FEATURE_CLZ
66156cd587Sjoerg	clz	ip, r0
67156cd587Sjoerg	clz	r3, r1
68156cd587Sjoerg	/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
69156cd587Sjoerg	sub	r3, r3, ip
70190e92d8Sjoerg#    if __ARM_ARCH_ISA_THUMB == 2
71190e92d8Sjoerg	adr	ip, LOCAL_LABEL(div0block) + 1
72190e92d8Sjoerg	sub	ip, ip, r3, lsl #1
73190e92d8Sjoerg#    else
74156cd587Sjoerg	adr	ip, LOCAL_LABEL(div0block)
75190e92d8Sjoerg#    endif
76156cd587Sjoerg	sub	ip, ip, r3, lsl #2
77156cd587Sjoerg	sub	ip, ip, r3, lsl #3
78156cd587Sjoerg	mov	r3, #0
79156cd587Sjoerg	bx	ip
80156cd587Sjoerg#  else
81190e92d8Sjoerg#    if __ARM_ARCH_ISA_THUMB == 2
82190e92d8Sjoerg#    error THUMB mode requires CLZ or UDIV
83190e92d8Sjoerg#    endif
84156cd587Sjoerg	str	r4, [sp, #-8]!
85156cd587Sjoerg
86156cd587Sjoerg	mov	r4, r0
87156cd587Sjoerg	adr	ip, LOCAL_LABEL(div0block)
88156cd587Sjoerg
89156cd587Sjoerg	lsr	r3, r4, #16
90156cd587Sjoerg	cmp	r3, r1
91156cd587Sjoerg	movhs	r4, r3
92156cd587Sjoerg	subhs	ip, ip, #(16 * 12)
93156cd587Sjoerg
94156cd587Sjoerg	lsr	r3, r4, #8
95156cd587Sjoerg	cmp	r3, r1
96156cd587Sjoerg	movhs	r4, r3
97156cd587Sjoerg	subhs	ip, ip, #(8 * 12)
98156cd587Sjoerg
99156cd587Sjoerg	lsr	r3, r4, #4
100156cd587Sjoerg	cmp	r3, r1
101156cd587Sjoerg	movhs	r4, r3
102156cd587Sjoerg	subhs	ip, #(4 * 12)
103156cd587Sjoerg
104156cd587Sjoerg	lsr	r3, r4, #2
105156cd587Sjoerg	cmp	r3, r1
106156cd587Sjoerg	movhs	r4, r3
107156cd587Sjoerg	subhs	ip, ip, #(2 * 12)
108156cd587Sjoerg
109156cd587Sjoerg	/* Last block, no need to update r3 or r4. */
110156cd587Sjoerg	cmp	r1, r4, lsr #1
111156cd587Sjoerg	subls	ip, ip, #(1 * 12)
112156cd587Sjoerg
113156cd587Sjoerg	ldr	r4, [sp], #8	/* restore r4, we are done with it. */
114156cd587Sjoerg	mov	r3, #0
115156cd587Sjoerg
116156cd587Sjoerg	JMP(ip)
117156cd587Sjoerg#  endif
118156cd587Sjoerg
119156cd587Sjoerg#define	IMM	#
120156cd587Sjoerg
121156cd587Sjoerg#define block(shift)                                                           \
122156cd587Sjoerg	cmp	r0, r1, lsl IMM shift;                                         \
123190e92d8Sjoerg	ITT(hs);                                                               \
124190e92d8Sjoerg	WIDE(addhs)	r3, r3, IMM (1 << shift);                              \
125190e92d8Sjoerg	WIDE(subhs)	r0, r0, r1, lsl IMM shift
126156cd587Sjoerg
127156cd587Sjoerg	block(31)
128156cd587Sjoerg	block(30)
129156cd587Sjoerg	block(29)
130156cd587Sjoerg	block(28)
131156cd587Sjoerg	block(27)
132156cd587Sjoerg	block(26)
133156cd587Sjoerg	block(25)
134156cd587Sjoerg	block(24)
135156cd587Sjoerg	block(23)
136156cd587Sjoerg	block(22)
137156cd587Sjoerg	block(21)
138156cd587Sjoerg	block(20)
139156cd587Sjoerg	block(19)
140156cd587Sjoerg	block(18)
141156cd587Sjoerg	block(17)
142156cd587Sjoerg	block(16)
143156cd587Sjoerg	block(15)
144156cd587Sjoerg	block(14)
145156cd587Sjoerg	block(13)
146156cd587Sjoerg	block(12)
147156cd587Sjoerg	block(11)
148156cd587Sjoerg	block(10)
149156cd587Sjoerg	block(9)
150156cd587Sjoerg	block(8)
151156cd587Sjoerg	block(7)
152156cd587Sjoerg	block(6)
153156cd587Sjoerg	block(5)
154156cd587Sjoerg	block(4)
155156cd587Sjoerg	block(3)
156156cd587Sjoerg	block(2)
157156cd587Sjoerg	block(1)
158156cd587SjoergLOCAL_LABEL(div0block):
159156cd587Sjoerg	block(0)
160156cd587Sjoerg
161156cd587Sjoerg	str	r0, [r2]
162156cd587Sjoerg	mov	r0, r3
163156cd587Sjoerg	JMP(lr)
164156cd587Sjoerg
165156cd587SjoergLOCAL_LABEL(quotient0):
166156cd587Sjoerg	str	r0, [r2]
167156cd587Sjoerg	mov	r0, #0
168156cd587Sjoerg	JMP(lr)
169156cd587Sjoerg
170156cd587SjoergLOCAL_LABEL(divby1):
171156cd587Sjoerg	mov	r3, #0
172156cd587Sjoerg	str	r3, [r2]
173156cd587Sjoerg	JMP(lr)
174156cd587Sjoerg#endif /* __ARM_ARCH_EXT_IDIV__ */
175156cd587Sjoerg
176156cd587SjoergLOCAL_LABEL(divby0):
177156cd587Sjoerg	mov	r0, #0
178156cd587Sjoerg#ifdef __ARM_EABI__
179156cd587Sjoerg	b	__aeabi_idiv0
180156cd587Sjoerg#else
181156cd587Sjoerg	JMP(lr)
182156cd587Sjoerg#endif
183156cd587Sjoerg
184156cd587SjoergEND_COMPILERRT_FUNCTION(__udivmodsi4)
185