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