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