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