]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S
Merge ^/head r305687 through r305890.
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / builtins / arm / udivmodsi4.S
1 /*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
2  *
3  *                     The LLVM Compiler Infrastructure
4  *
5  * This file is dual licensed under the MIT and the University of Illinois Open
6  * Source Licenses. See LICENSE.TXT for details.
7  *
8  *===----------------------------------------------------------------------===//
9  *
10  * This file implements the __udivmodsi4 (32-bit unsigned integer divide and
11  * modulus) function for the ARM 32-bit architecture.
12  *
13  *===----------------------------------------------------------------------===*/
14
15 #include "../assembly.h"
16
17         .syntax unified
18         .text
19
20 #if __ARM_ARCH_ISA_THUMB == 2
21         .thumb
22 #endif
23
24 @ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
25 @                           unsigned int *remainder)
26 @   Calculate the quotient and remainder of the (unsigned) division.  The return
27 @   value is the quotient, the remainder is placed in the variable.
28
29         .p2align 2
30 #if __ARM_ARCH_ISA_THUMB == 2
31 DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
32 #else
33 DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
34 #endif
35 #if __ARM_ARCH_EXT_IDIV__
36         tst     r1, r1
37         beq     LOCAL_LABEL(divby0)
38         mov     r3, r0
39         udiv    r0, r3, r1
40         mls     r1, r0, r1, r3
41         str     r1, [r2]
42         bx      lr
43 #else
44         cmp     r1, #1
45         bcc     LOCAL_LABEL(divby0)
46         beq     LOCAL_LABEL(divby1)
47         cmp     r0, r1
48         bcc     LOCAL_LABEL(quotient0)
49         /*
50          * Implement division using binary long division algorithm.
51          *
52          * r0 is the numerator, r1 the denominator.
53          *
54          * The code before JMP computes the correct shift I, so that
55          * r0 and (r1 << I) have the highest bit set in the same position.
56          * At the time of JMP, ip := .Ldiv0block - 12 * I.
57          * This depends on the fixed instruction size of block.
58          * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
59          *
60          * block(shift) implements the test-and-update-quotient core.
61          * It assumes (r0 << shift) can be computed without overflow and
62          * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
63          */
64
65 #  ifdef __ARM_FEATURE_CLZ
66         clz     ip, r0
67         clz     r3, r1
68         /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
69         sub     r3, r3, ip
70 #    if __ARM_ARCH_ISA_THUMB == 2
71         adr     ip, LOCAL_LABEL(div0block) + 1
72         sub     ip, ip, r3, lsl #1
73 #    else
74         adr     ip, LOCAL_LABEL(div0block)
75 #    endif
76         sub     ip, ip, r3, lsl #2
77         sub     ip, ip, r3, lsl #3
78         mov     r3, #0
79         bx      ip
80 #  else
81 #    if __ARM_ARCH_ISA_THUMB == 2
82 #    error THUMB mode requires CLZ or UDIV
83 #    endif
84         str     r4, [sp, #-8]!
85
86         mov     r4, r0
87         adr     ip, LOCAL_LABEL(div0block)
88
89         lsr     r3, r4, #16
90         cmp     r3, r1
91         movhs   r4, r3
92         subhs   ip, ip, #(16 * 12)
93
94         lsr     r3, r4, #8
95         cmp     r3, r1
96         movhs   r4, r3
97         subhs   ip, ip, #(8 * 12)
98
99         lsr     r3, r4, #4
100         cmp     r3, r1
101         movhs   r4, r3
102         subhs   ip, #(4 * 12)
103
104         lsr     r3, r4, #2
105         cmp     r3, r1
106         movhs   r4, r3
107         subhs   ip, ip, #(2 * 12)
108
109         /* Last block, no need to update r3 or r4. */
110         cmp     r1, r4, lsr #1
111         subls   ip, ip, #(1 * 12)
112
113         ldr     r4, [sp], #8    /* restore r4, we are done with it. */
114         mov     r3, #0
115
116         JMP(ip)
117 #  endif
118
119 #define IMM     #
120
121 #define block(shift)                                                           \
122         cmp     r0, r1, lsl IMM shift;                                         \
123         ITT(hs);                                                               \
124         WIDE(addhs)     r3, r3, IMM (1 << shift);                              \
125         WIDE(subhs)     r0, r0, r1, lsl IMM shift
126
127         block(31)
128         block(30)
129         block(29)
130         block(28)
131         block(27)
132         block(26)
133         block(25)
134         block(24)
135         block(23)
136         block(22)
137         block(21)
138         block(20)
139         block(19)
140         block(18)
141         block(17)
142         block(16)
143         block(15)
144         block(14)
145         block(13)
146         block(12)
147         block(11)
148         block(10)
149         block(9)
150         block(8)
151         block(7)
152         block(6)
153         block(5)
154         block(4)
155         block(3)
156         block(2)
157         block(1)
158 LOCAL_LABEL(div0block):
159         block(0)
160
161         str     r0, [r2]
162         mov     r0, r3
163         JMP(lr)
164
165 LOCAL_LABEL(quotient0):
166         str     r0, [r2]
167         mov     r0, #0
168         JMP(lr)
169
170 LOCAL_LABEL(divby1):
171         mov     r3, #0
172         str     r3, [r2]
173         JMP(lr)
174 #endif /* __ARM_ARCH_EXT_IDIV__ */
175
176 LOCAL_LABEL(divby0):
177         mov     r0, #0
178 #ifdef __ARM_EABI__
179         b       __aeabi_idiv0
180 #else
181         JMP(lr)
182 #endif
183
184 END_COMPILERRT_FUNCTION(__udivmodsi4)
185
186 NO_EXEC_STACK_DIRECTIVE
187